@aztec/pxe 0.41.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dest/config/index.d.ts.map +1 -1
  2. package/dest/config/index.js +5 -2
  3. package/dest/contract_data_oracle/index.d.ts +1 -0
  4. package/dest/contract_data_oracle/index.d.ts.map +1 -1
  5. package/dest/contract_data_oracle/index.js +7 -1
  6. package/dest/contract_data_oracle/private_functions_tree.d.ts.map +1 -1
  7. package/dest/contract_data_oracle/private_functions_tree.js +2 -2
  8. package/dest/database/deferred_note_dao.d.ts +2 -2
  9. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  10. package/dest/database/deferred_note_dao.js +2 -2
  11. package/dest/database/incoming_note_dao.d.ts +73 -0
  12. package/dest/database/incoming_note_dao.d.ts.map +1 -0
  13. package/dest/database/incoming_note_dao.js +92 -0
  14. package/dest/database/kv_pxe_database.d.ts +10 -7
  15. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  16. package/dest/database/kv_pxe_database.js +149 -78
  17. package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +7 -12
  18. package/dest/database/outgoing_note_dao.d.ts.map +1 -0
  19. package/dest/database/outgoing_note_dao.js +83 -0
  20. package/dest/database/pxe_database.d.ts +21 -9
  21. package/dest/database/pxe_database.d.ts.map +1 -1
  22. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  23. package/dest/database/pxe_database_test_suite.js +71 -24
  24. package/dest/kernel_oracle/index.d.ts +4 -4
  25. package/dest/kernel_oracle/index.d.ts.map +1 -1
  26. package/dest/kernel_oracle/index.js +6 -17
  27. package/dest/kernel_prover/kernel_prover.d.ts +3 -0
  28. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  29. package/dest/kernel_prover/kernel_prover.js +44 -8
  30. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts +2 -1
  31. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts.map +1 -1
  32. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.js +32 -12
  33. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts +1 -1
  34. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts.map +1 -1
  35. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.js +9 -7
  36. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.d.ts.map +1 -1
  37. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.js +7 -3
  38. package/dest/kernel_prover/proving_data_oracle.d.ts +6 -6
  39. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -1
  40. package/dest/note_processor/note_processor.d.ts +23 -20
  41. package/dest/note_processor/note_processor.d.ts.map +1 -1
  42. package/dest/note_processor/note_processor.js +123 -76
  43. package/dest/note_processor/produce_note_dao.d.ts +13 -4
  44. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  45. package/dest/note_processor/produce_note_dao.js +88 -31
  46. package/dest/pxe_http/pxe_http_server.js +3 -3
  47. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  48. package/dest/pxe_service/create_pxe_service.js +4 -2
  49. package/dest/pxe_service/pxe_service.d.ts +14 -6
  50. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  51. package/dest/pxe_service/pxe_service.js +139 -87
  52. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
  53. package/dest/pxe_service/test/pxe_test_suite.js +3 -16
  54. package/dest/simulator_oracle/index.d.ts +1 -0
  55. package/dest/simulator_oracle/index.d.ts.map +1 -1
  56. package/dest/simulator_oracle/index.js +5 -2
  57. package/dest/synchronizer/synchronizer.d.ts +9 -2
  58. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  59. package/dest/synchronizer/synchronizer.js +43 -34
  60. package/package.json +14 -14
  61. package/src/config/index.ts +11 -1
  62. package/src/contract_data_oracle/index.ts +7 -0
  63. package/src/contract_data_oracle/private_functions_tree.ts +3 -1
  64. package/src/database/deferred_note_dao.ts +1 -1
  65. package/src/database/{note_dao.ts → incoming_note_dao.ts} +10 -7
  66. package/src/database/kv_pxe_database.ts +127 -29
  67. package/src/database/outgoing_note_dao.ts +90 -0
  68. package/src/database/pxe_database.ts +23 -9
  69. package/src/database/pxe_database_test_suite.ts +93 -29
  70. package/src/kernel_oracle/index.ts +4 -17
  71. package/src/kernel_prover/kernel_prover.ts +76 -16
  72. package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts +79 -8
  73. package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.ts +9 -5
  74. package/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts +13 -1
  75. package/src/kernel_prover/proving_data_oracle.ts +5 -6
  76. package/src/note_processor/note_processor.ts +191 -121
  77. package/src/note_processor/produce_note_dao.ts +164 -50
  78. package/src/pxe_http/pxe_http_server.ts +2 -2
  79. package/src/pxe_service/create_pxe_service.ts +3 -1
  80. package/src/pxe_service/pxe_service.ts +210 -149
  81. package/src/pxe_service/test/pxe_test_suite.ts +0 -20
  82. package/src/simulator_oracle/index.ts +5 -1
  83. package/src/synchronizer/synchronizer.ts +55 -50
  84. package/dest/database/note_dao.d.ts.map +0 -1
  85. package/dest/database/note_dao.js +0 -89
@@ -1,18 +1,24 @@
1
1
  import {
2
2
  type AuthWitness,
3
3
  type AztecNode,
4
+ EncryptedNoteTxL2Logs,
4
5
  EncryptedTxL2Logs,
6
+ type EventMetadata,
5
7
  ExtendedNote,
6
8
  type FunctionCall,
7
9
  type GetUnencryptedLogsResponse,
10
+ type IncomingNotesFilter,
11
+ L1EventPayload,
8
12
  type L2Block,
9
13
  type LogFilter,
10
14
  MerkleTreeId,
11
- type NoteFilter,
15
+ type OutgoingNotesFilter,
12
16
  type PXE,
17
+ type PXEInfo,
13
18
  type ProofCreator,
14
19
  SimulatedTx,
15
20
  SimulationError,
21
+ TaggedLog,
16
22
  Tx,
17
23
  type TxEffect,
18
24
  type TxExecutionRequest,
@@ -21,27 +27,24 @@ import {
21
27
  UnencryptedTxL2Logs,
22
28
  isNoirCallStackUnresolved,
23
29
  } from '@aztec/circuit-types';
24
- import { type TxPXEProcessingStats } from '@aztec/circuit-types/stats';
25
30
  import {
26
31
  AztecAddress,
27
- CallRequest,
28
32
  type CompleteAddress,
29
- FunctionData,
30
- MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
31
33
  type PartialAddress,
32
- type PrivateKernelTailCircuitPublicInputs,
33
- type PublicCallRequest,
34
34
  computeContractClassId,
35
35
  getContractClassFromArtifact,
36
36
  } from '@aztec/circuits.js';
37
37
  import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
38
38
  import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
39
- import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
40
- import { type Fq, Fr } from '@aztec/foundation/fields';
39
+ import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
41
40
  import { SerialQueue } from '@aztec/foundation/fifo';
42
41
  import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
43
- import { Timer } from '@aztec/foundation/timer';
44
42
  import { type KeyStore } from '@aztec/key-store';
43
+ import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
44
+ import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
45
+ import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
46
+ import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
47
+ import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint';
45
48
  import {
46
49
  type AcirSimulator,
47
50
  type ExecutionResult,
@@ -58,10 +61,11 @@ import { type NodeInfo } from '@aztec/types/interfaces';
58
61
 
59
62
  import { type PXEServiceConfig, getPackageInfo } from '../config/index.js';
60
63
  import { ContractDataOracle } from '../contract_data_oracle/index.js';
64
+ import { IncomingNoteDao } from '../database/incoming_note_dao.js';
61
65
  import { type PxeDatabase } from '../database/index.js';
62
- import { NoteDao } from '../database/note_dao.js';
63
66
  import { KernelOracle } from '../kernel_oracle/index.js';
64
67
  import { KernelProver } from '../kernel_prover/kernel_prover.js';
68
+ import { TestProofCreator } from '../kernel_prover/test/test_circuit_prover.js';
65
69
  import { getAcirSimulator } from '../simulator/index.js';
66
70
  import { Synchronizer } from '../synchronizer/index.js';
67
71
 
@@ -73,11 +77,13 @@ export class PXEService implements PXE {
73
77
  private contractDataOracle: ContractDataOracle;
74
78
  private simulator: AcirSimulator;
75
79
  private log: DebugLogger;
76
- private nodeVersion: string;
80
+ private packageVersion: string;
77
81
  // serialize synchronizer and calls to proveTx.
78
82
  // ensures that state is not changed while simulating
79
83
  private jobQueue = new SerialQueue();
80
84
 
85
+ private fakeProofCreator = new TestProofCreator();
86
+
81
87
  constructor(
82
88
  private keyStore: KeyStore,
83
89
  private node: AztecNode,
@@ -90,7 +96,7 @@ export class PXEService implements PXE {
90
96
  this.synchronizer = new Synchronizer(node, db, this.jobQueue, logSuffix);
91
97
  this.contractDataOracle = new ContractDataOracle(db);
92
98
  this.simulator = getAcirSimulator(db, node, keyStore, this.contractDataOracle);
93
- this.nodeVersion = getPackageInfo().version;
99
+ this.packageVersion = getPackageInfo().version;
94
100
 
95
101
  this.jobQueue.start();
96
102
  }
@@ -122,11 +128,7 @@ export class PXEService implements PXE {
122
128
  }
123
129
 
124
130
  count++;
125
- this.synchronizer.addAccount(
126
- address.publicKeys.masterIncomingViewingPublicKey,
127
- this.keyStore,
128
- this.config.l2StartingBlock,
129
- );
131
+ await this.synchronizer.addAccount(address.address, this.keyStore, this.config.l2StartingBlock);
130
132
  }
131
133
 
132
134
  if (count > 0) {
@@ -178,6 +180,10 @@ export class PXEService implements PXE {
178
180
  return artifact && getContractClassFromArtifact(artifact);
179
181
  }
180
182
 
183
+ public getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
184
+ return this.db.getContractArtifact(id);
185
+ }
186
+
181
187
  public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
182
188
  const accounts = await this.keyStore.getAccounts();
183
189
  const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress);
@@ -185,10 +191,7 @@ export class PXEService implements PXE {
185
191
  this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
186
192
  return accountCompleteAddress;
187
193
  } else {
188
- const masterIncomingViewingPublicKey = await this.keyStore.getMasterIncomingViewingPublicKey(
189
- accountCompleteAddress.address,
190
- );
191
- this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock);
194
+ await this.synchronizer.addAccount(accountCompleteAddress.address, this.keyStore, this.config.l2StartingBlock);
192
195
  this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
193
196
  this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
194
197
  }
@@ -259,6 +262,7 @@ export class PXEService implements PXE {
259
262
  );
260
263
  }
261
264
  await this.db.addContractArtifact(contractClassId, artifact);
265
+ await this.node.addContractArtifact(instance.address, artifact);
262
266
  } else {
263
267
  // Otherwise, make sure there is an artifact already registered for that class id
264
268
  artifact = await this.db.getContractArtifact(instance.contractClassId);
@@ -285,19 +289,40 @@ export class PXEService implements PXE {
285
289
  return await this.node.getPublicStorageAt(contract, slot);
286
290
  }
287
291
 
288
- public async getNotes(filter: NoteFilter): Promise<ExtendedNote[]> {
289
- const noteDaos = await this.db.getNotes(filter);
292
+ public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
293
+ const noteDaos = await this.db.getIncomingNotes(filter);
290
294
 
291
- // TODO(benesjan): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
292
- // key derivation will affect all this
295
+ // TODO(#6531): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
296
+ // key rotation will affect this
293
297
  const extendedNotes = noteDaos.map(async dao => {
294
298
  let owner = filter.owner;
295
299
  if (owner === undefined) {
296
300
  const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
297
- address.publicKeys.masterIncomingViewingPublicKey.equals(dao.publicKey),
301
+ address.publicKeys.masterIncomingViewingPublicKey.equals(dao.ivpkM),
298
302
  );
299
303
  if (completeAddresses === undefined) {
300
- throw new Error(`Cannot find complete address for public key ${dao.publicKey.toString()}`);
304
+ throw new Error(`Cannot find complete address for IvpkM ${dao.ivpkM.toString()}`);
305
+ }
306
+ owner = completeAddresses.address;
307
+ }
308
+ return new ExtendedNote(dao.note, owner, dao.contractAddress, dao.storageSlot, dao.noteTypeId, dao.txHash);
309
+ });
310
+ return Promise.all(extendedNotes);
311
+ }
312
+
313
+ public async getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]> {
314
+ const noteDaos = await this.db.getOutgoingNotes(filter);
315
+
316
+ // TODO(#6532): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
317
+ // key rotation will affect this
318
+ const extendedNotes = noteDaos.map(async dao => {
319
+ let owner = filter.owner;
320
+ if (owner === undefined) {
321
+ const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
322
+ address.publicKeys.masterOutgoingViewingPublicKey.equals(dao.ovpkM),
323
+ );
324
+ if (completeAddresses === undefined) {
325
+ throw new Error(`Cannot find complete address for OvpkM ${dao.ovpkM.toString()}`);
301
326
  }
302
327
  owner = completeAddresses.address;
303
328
  }
@@ -318,13 +343,15 @@ export class PXEService implements PXE {
318
343
  }
319
344
 
320
345
  for (const nonce of nonces) {
321
- const { innerNoteHash, siloedNoteHash, innerNullifier } = await this.simulator.computeNoteHashAndNullifier(
322
- note.contractAddress,
323
- nonce,
324
- note.storageSlot,
325
- note.noteTypeId,
326
- note.note,
327
- );
346
+ const { innerNoteHash, siloedNoteHash, innerNullifier } =
347
+ await this.simulator.computeNoteHashAndOptionallyANullifier(
348
+ note.contractAddress,
349
+ nonce,
350
+ note.storageSlot,
351
+ note.noteTypeId,
352
+ true,
353
+ note.note,
354
+ );
328
355
 
329
356
  const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
330
357
  if (index === undefined) {
@@ -338,7 +365,7 @@ export class PXEService implements PXE {
338
365
  }
339
366
 
340
367
  await this.db.addNote(
341
- new NoteDao(
368
+ new IncomingNoteDao(
342
369
  note.note,
343
370
  note.contractAddress,
344
371
  note.storageSlot,
@@ -354,6 +381,54 @@ export class PXEService implements PXE {
354
381
  }
355
382
  }
356
383
 
384
+ public async addNullifiedNote(note: ExtendedNote) {
385
+ const owner = await this.db.getCompleteAddress(note.owner);
386
+ if (!owner) {
387
+ throw new Error(`Unknown account: ${note.owner.toString()}`);
388
+ }
389
+
390
+ const nonces = await this.getNoteNonces(note);
391
+ if (nonces.length === 0) {
392
+ throw new Error(`Cannot find the note in tx: ${note.txHash}.`);
393
+ }
394
+
395
+ for (const nonce of nonces) {
396
+ const { innerNoteHash, siloedNoteHash, innerNullifier } =
397
+ await this.simulator.computeNoteHashAndOptionallyANullifier(
398
+ note.contractAddress,
399
+ nonce,
400
+ note.storageSlot,
401
+ note.noteTypeId,
402
+ false,
403
+ note.note,
404
+ );
405
+
406
+ if (!innerNullifier.equals(Fr.ZERO)) {
407
+ throw new Error('Unexpectedly received non-zero nullifier.');
408
+ }
409
+
410
+ const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
411
+ if (index === undefined) {
412
+ throw new Error('Note does not exist.');
413
+ }
414
+
415
+ await this.db.addNullifiedNote(
416
+ new IncomingNoteDao(
417
+ note.note,
418
+ note.contractAddress,
419
+ note.storageSlot,
420
+ note.noteTypeId,
421
+ note.txHash,
422
+ nonce,
423
+ innerNoteHash,
424
+ Fr.ZERO, // We are not able to derive
425
+ index,
426
+ owner.publicKeys.masterIncomingViewingPublicKey,
427
+ ),
428
+ );
429
+ }
430
+ }
431
+
357
432
  /**
358
433
  * Finds the nonce(s) for a given note.
359
434
  * @param note - The note to find the nonces for.
@@ -373,11 +448,12 @@ export class PXEService implements PXE {
373
448
  // Remove this once notes added from public also include nonces.
374
449
  {
375
450
  const publicNoteNonce = Fr.ZERO;
376
- const { siloedNoteHash } = await this.simulator.computeNoteHashAndNullifier(
451
+ const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
377
452
  note.contractAddress,
378
453
  publicNoteNonce,
379
454
  note.storageSlot,
380
455
  note.noteTypeId,
456
+ false,
381
457
  note.note,
382
458
  );
383
459
  if (tx.noteHashes.some(hash => hash.equals(siloedNoteHash))) {
@@ -394,11 +470,12 @@ export class PXEService implements PXE {
394
470
  }
395
471
 
396
472
  const nonce = computeNoteHashNonce(firstNullifier, i);
397
- const { siloedNoteHash } = await this.simulator.computeNoteHashAndNullifier(
473
+ const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
398
474
  note.contractAddress,
399
475
  nonce,
400
476
  note.storageSlot,
401
477
  note.noteTypeId,
478
+ false,
402
479
  note.note,
403
480
  );
404
481
  if (hash.equals(siloedNoteHash)) {
@@ -417,8 +494,14 @@ export class PXEService implements PXE {
417
494
  return await this.node.getBlock(blockNumber);
418
495
  }
419
496
 
420
- public async proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean) {
421
- return (await this.simulateTx(txRequest, simulatePublic)).tx;
497
+ public proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx> {
498
+ return this.jobQueue.put(async () => {
499
+ const simulatedTx = await this.#simulateAndProve(txRequest, this.proofCreator, undefined);
500
+ if (simulatePublic) {
501
+ simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
502
+ }
503
+ return simulatedTx.tx;
504
+ });
422
505
  }
423
506
 
424
507
  public async simulateTx(
@@ -426,29 +509,16 @@ export class PXEService implements PXE {
426
509
  simulatePublic: boolean,
427
510
  msgSender: AztecAddress | undefined = undefined,
428
511
  ): Promise<SimulatedTx> {
429
- if (!txRequest.functionData.isPrivate) {
430
- throw new Error(`Public entrypoints are not allowed`);
431
- }
432
512
  return await this.jobQueue.put(async () => {
433
- const timer = new Timer();
434
- const simulatedTx = await this.#simulateAndProve(txRequest, msgSender);
435
- // We log only if the msgSender is undefined, as simulating with a different msgSender
436
- // is unlikely to be a real transaction, and likely to be only used to read data.
437
- // Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
438
- // If we log, the `getTxHash` function will throw.
439
-
440
- if (!msgSender) {
441
- this.log.debug(`Processed private part of ${simulatedTx.tx.getTxHash()}`, {
442
- eventName: 'tx-pxe-processing',
443
- duration: timer.ms(),
444
- ...simulatedTx.tx.getStats(),
445
- } satisfies TxPXEProcessingStats);
446
- }
447
-
513
+ const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
448
514
  if (simulatePublic) {
449
515
  simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
450
516
  }
451
517
 
518
+ // We log only if the msgSender is undefined, as simulating with a different msgSender
519
+ // is unlikely to be a real transaction, and likely to be only used to read data.
520
+ // Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
521
+ // If we log, the `getTxHash` function will throw.
452
522
  if (!msgSender) {
453
523
  this.log.info(`Executed local simulation for ${simulatedTx.tx.getTxHash()}`);
454
524
  }
@@ -518,29 +588,49 @@ export class PXEService implements PXE {
518
588
  }
519
589
 
520
590
  return {
591
+ name: functionDao.name,
521
592
  args: encodeArguments(functionDao, args),
522
- functionData: FunctionData.fromAbi(functionDao),
593
+ selector: FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
594
+ type: functionDao.functionType,
523
595
  to,
524
596
  isStatic: functionDao.isStatic,
597
+ returnTypes: functionDao.returnTypes,
525
598
  };
526
599
  }
527
600
 
528
601
  public async getNodeInfo(): Promise<NodeInfo> {
529
- const [version, chainId, contractAddresses] = await Promise.all([
602
+ const [nodeVersion, protocolVersion, chainId, contractAddresses, protocolContractAddresses] = await Promise.all([
603
+ this.node.getNodeVersion(),
530
604
  this.node.getVersion(),
531
605
  this.node.getChainId(),
532
606
  this.node.getL1ContractAddresses(),
607
+ this.node.getProtocolContractAddresses(),
533
608
  ]);
534
609
 
535
610
  const nodeInfo: NodeInfo = {
536
- nodeVersion: this.nodeVersion,
611
+ nodeVersion,
537
612
  chainId,
538
- protocolVersion: version,
613
+ protocolVersion,
539
614
  l1ContractAddresses: contractAddresses,
615
+ protocolContractAddresses: protocolContractAddresses,
540
616
  };
617
+
541
618
  return nodeInfo;
542
619
  }
543
620
 
621
+ public getPXEInfo(): Promise<PXEInfo> {
622
+ return Promise.resolve({
623
+ pxeVersion: this.packageVersion,
624
+ protocolContractAddresses: {
625
+ classRegisterer: ClassRegistererAddress,
626
+ gasToken: getCanonicalGasToken().address,
627
+ instanceDeployer: getCanonicalInstanceDeployer().address,
628
+ keyRegistry: getCanonicalKeyRegistryAddress(),
629
+ multiCallEntrypoint: getCanonicalMultiCallEntrypointAddress(),
630
+ },
631
+ });
632
+ }
633
+
544
634
  /**
545
635
  * Retrieves the simulation parameters required to run an ACIR simulation.
546
636
  * This includes the contract address, function artifact, and historical tree roots.
@@ -550,14 +640,10 @@ export class PXEService implements PXE {
550
640
  */
551
641
  async #getSimulationParameters(execRequest: FunctionCall | TxExecutionRequest) {
552
642
  const contractAddress = (execRequest as FunctionCall).to ?? (execRequest as TxExecutionRequest).origin;
553
- const functionArtifact = await this.contractDataOracle.getFunctionArtifact(
554
- contractAddress,
555
- execRequest.functionData.selector,
556
- );
557
- const debug = await this.contractDataOracle.getFunctionDebugMetadata(
558
- contractAddress,
559
- execRequest.functionData.selector,
560
- );
643
+ const functionSelector =
644
+ (execRequest as FunctionCall).selector ?? (execRequest as TxExecutionRequest).functionSelector;
645
+ const functionArtifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, functionSelector);
646
+ const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, functionSelector);
561
647
 
562
648
  return {
563
649
  contractAddress,
@@ -649,31 +735,31 @@ export class PXEService implements PXE {
649
735
  * the function will also include the new contract's public functions in the transaction object.
650
736
  *
651
737
  * @param txExecutionRequest - The transaction request to be simulated and proved.
652
- * @param signature - The ECDSA signature for the transaction request.
738
+ * @param proofCreator - The proof creator to use for proving the execution.
653
739
  * @param msgSender - (Optional) The message sender to use for the simulation.
654
- * @returns An object tract contains:
740
+ * @returns An object that contains:
655
741
  * A private transaction object containing the proof, public inputs, and encrypted logs.
656
742
  * The return values of the private execution
657
743
  */
658
- async #simulateAndProve(txExecutionRequest: TxExecutionRequest, msgSender?: AztecAddress) {
744
+ async #simulateAndProve(
745
+ txExecutionRequest: TxExecutionRequest,
746
+ proofCreator: ProofCreator,
747
+ msgSender?: AztecAddress,
748
+ ): Promise<SimulatedTx> {
659
749
  // Get values that allow us to reconstruct the block hash
660
750
  const executionResult = await this.#simulate(txExecutionRequest, msgSender);
661
751
 
662
752
  const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
663
- const kernelProver = new KernelProver(kernelOracle, this.proofCreator);
753
+ const kernelProver = new KernelProver(kernelOracle, proofCreator);
664
754
  this.log.debug(`Executing kernel prover...`);
665
755
  const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult);
666
756
 
667
- const noteEncryptedLogs = new EncryptedTxL2Logs([collectSortedNoteEncryptedLogs(executionResult)]);
757
+ const noteEncryptedLogs = new EncryptedNoteTxL2Logs([collectSortedNoteEncryptedLogs(executionResult)]);
668
758
  const unencryptedLogs = new UnencryptedTxL2Logs([collectSortedUnencryptedLogs(executionResult)]);
669
759
  const encryptedLogs = new EncryptedTxL2Logs([collectSortedEncryptedLogs(executionResult)]);
670
760
  const enqueuedPublicFunctions = collectEnqueuedPublicFunctionCalls(executionResult);
671
761
  const teardownPublicFunction = collectPublicTeardownFunctionCall(executionResult);
672
762
 
673
- // HACK(#1639): Manually patches the ordering of the public call stack
674
- // TODO(#757): Enforce proper ordering of enqueued public calls
675
- await this.patchPublicCallStackOrdering(publicInputs, enqueuedPublicFunctions);
676
-
677
763
  const tx = new Tx(
678
764
  publicInputs,
679
765
  proof.binaryProof,
@@ -724,76 +810,6 @@ export class PXEService implements PXE {
724
810
  );
725
811
  }
726
812
 
727
- // HACK(#1639): this is a hack to fix ordering of public calls enqueued in the call stack. Since the private kernel
728
- // cannot keep track of side effects that happen after or before a nested call, we override the public call stack
729
- // it emits with whatever we got from the simulator collected enqueued calls. As a sanity check, we at least verify
730
- // that the elements are the same, so we are only tweaking their ordering.
731
- // See yarn-project/end-to-end/src/e2e_ordering.test.ts
732
- // See https://github.com/AztecProtocol/aztec-packages/issues/1615
733
- // TODO(#757): Enforce proper ordering of enqueued public calls
734
- private async patchPublicCallStackOrdering(
735
- publicInputs: PrivateKernelTailCircuitPublicInputs,
736
- enqueuedPublicCalls: PublicCallRequest[],
737
- ) {
738
- if (!publicInputs.forPublic) {
739
- return;
740
- }
741
-
742
- const enqueuedPublicCallStackItems = await Promise.all(enqueuedPublicCalls.map(c => c.toCallRequest()));
743
-
744
- // Validate all items in enqueued public calls are in the kernel emitted stack
745
- const enqueuedRevertiblePublicCallStackItems = enqueuedPublicCallStackItems.filter(enqueued =>
746
- publicInputs.forPublic!.end.publicCallStack.find(item => item.equals(enqueued)),
747
- );
748
-
749
- const revertibleStackSize = arrayNonEmptyLength(publicInputs.forPublic.end.publicCallStack, item => item.isEmpty());
750
-
751
- if (enqueuedRevertiblePublicCallStackItems.length !== revertibleStackSize) {
752
- throw new Error(
753
- `Enqueued revertible public function calls and revertible public call stack do not match.\nEnqueued calls: ${enqueuedRevertiblePublicCallStackItems
754
- .map(h => h.hash.toString())
755
- .join(', ')}\nPublic call stack: ${publicInputs.forPublic.end.publicCallStack
756
- .map(i => i.toString())
757
- .join(', ')}`,
758
- );
759
- }
760
-
761
- // Override kernel output
762
- publicInputs.forPublic.end.publicCallStack = padArrayEnd(
763
- enqueuedRevertiblePublicCallStackItems,
764
- CallRequest.empty(),
765
- MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
766
- );
767
-
768
- // Do the same for non-revertible
769
-
770
- const enqueuedNonRevertiblePublicCallStackItems = enqueuedPublicCallStackItems.filter(enqueued =>
771
- publicInputs.forPublic!.endNonRevertibleData.publicCallStack.find(item => item.equals(enqueued)),
772
- );
773
-
774
- const nonRevertibleStackSize = arrayNonEmptyLength(
775
- publicInputs.forPublic.endNonRevertibleData.publicCallStack,
776
- item => item.isEmpty(),
777
- );
778
-
779
- if (enqueuedNonRevertiblePublicCallStackItems.length !== nonRevertibleStackSize) {
780
- throw new Error(
781
- `Enqueued non-revertible public function calls and non-revertible public call stack do not match.\nEnqueued calls: ${enqueuedNonRevertiblePublicCallStackItems
782
- .map(h => h.hash.toString())
783
- .join(', ')}\nPublic call stack: ${publicInputs.forPublic.endNonRevertibleData.publicCallStack
784
- .map(i => i.toString())
785
- .join(', ')}`,
786
- );
787
- }
788
-
789
- // Override kernel output
790
- publicInputs.forPublic.endNonRevertibleData.publicCallStack = padArrayEnd(
791
- enqueuedNonRevertiblePublicCallStackItems,
792
- CallRequest.empty(),
793
- MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
794
- );
795
- }
796
-
797
813
  public async isGlobalStateSynchronized() {
798
814
  return await this.synchronizer.isGlobalStateSynchronized();
799
815
  }
@@ -806,6 +822,10 @@ export class PXEService implements PXE {
806
822
  return Promise.resolve(this.synchronizer.getSyncStatus());
807
823
  }
808
824
 
825
+ public getSyncStats() {
826
+ return Promise.resolve(this.synchronizer.getSyncStats());
827
+ }
828
+
809
829
  public async isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
810
830
  return !!(await this.node.getContractClass(id));
811
831
  }
@@ -813,4 +833,45 @@ export class PXEService implements PXE {
813
833
  public async isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
814
834
  return !!(await this.node.getContract(address));
815
835
  }
836
+
837
+ public async getEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]> {
838
+ const blocks = await this.node.getBlocks(from, limit);
839
+
840
+ const txEffects = blocks.flatMap(block => block.body.txEffects);
841
+ const encryptedTxLogs = txEffects.flatMap(txEffect => txEffect.encryptedLogs);
842
+
843
+ const encryptedLogs = encryptedTxLogs.flatMap(encryptedTxLog => encryptedTxLog.unrollLogs());
844
+
845
+ const ivsk = await this.keyStore.getMasterSecretKey(ivpk);
846
+
847
+ const visibleEvents = encryptedLogs
848
+ .map(encryptedLog => TaggedLog.decryptAsIncoming(encryptedLog, ivsk, L1EventPayload))
849
+ .filter(item => item !== undefined) as TaggedLog<L1EventPayload>[];
850
+
851
+ const decodedEvents = visibleEvents
852
+ .map(visibleEvent => {
853
+ if (visibleEvent.payload === undefined) {
854
+ return undefined;
855
+ }
856
+ if (!FunctionSelector.fromField(visibleEvent.payload.eventTypeId).equals(eventMetadata.functionSelector)) {
857
+ return undefined;
858
+ }
859
+ if (visibleEvent.payload.event.items.length !== eventMetadata.fieldNames.length) {
860
+ throw new Error(
861
+ 'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length',
862
+ );
863
+ }
864
+
865
+ return eventMetadata.fieldNames.reduce(
866
+ (acc, curr, i) => ({
867
+ ...acc,
868
+ [curr]: visibleEvent.payload.event.items[i],
869
+ }),
870
+ {} as T,
871
+ );
872
+ })
873
+ .filter(visibleEvent => visibleEvent !== undefined) as T[];
874
+
875
+ return decodedEvents;
876
+ }
816
877
  }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  type PXE,
3
- TxExecutionRequest,
4
3
  randomContractArtifact,
5
4
  randomContractInstanceWithAddress,
6
5
  randomDeployedContract,
@@ -9,11 +8,9 @@ import {
9
8
  AztecAddress,
10
9
  CompleteAddress,
11
10
  Fr,
12
- FunctionData,
13
11
  INITIAL_L2_BLOCK_NUM,
14
12
  Point,
15
13
  PublicKeys,
16
- TxContext,
17
14
  getContractClassFromArtifact,
18
15
  } from '@aztec/circuits.js';
19
16
 
@@ -126,23 +123,6 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise<PXE>) =>
126
123
  await expect(pxe.registerContract({ instance, artifact })).rejects.toThrow(/Artifact does not match/i);
127
124
  });
128
125
 
129
- it('throws when simulating a tx targeting public entrypoint', async () => {
130
- const functionData = FunctionData.empty();
131
- functionData.isPrivate = false;
132
- const txExecutionRequest = TxExecutionRequest.from({
133
- origin: AztecAddress.random(),
134
- firstCallArgsHash: new Fr(0),
135
- functionData,
136
- txContext: TxContext.empty(),
137
- argsOfCalls: [],
138
- authWitnesses: [],
139
- });
140
-
141
- await expect(async () => await pxe.proveTx(txExecutionRequest, false)).rejects.toThrow(
142
- 'Public entrypoints are not allowed',
143
- );
144
- });
145
-
146
126
  // Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `simulateUnconstrained` here as it requires
147
127
  // a larger setup and it's sufficiently tested in the e2e tests.
148
128
 
@@ -78,7 +78,7 @@ export class SimulatorOracle implements DBOracle {
78
78
  }
79
79
 
80
80
  async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) {
81
- const noteDaos = await this.db.getNotes({
81
+ const noteDaos = await this.db.getIncomingNotes({
82
82
  contractAddress,
83
83
  storageSlot,
84
84
  status,
@@ -230,4 +230,8 @@ export class SimulatorOracle implements DBOracle {
230
230
  public async getBlockNumber(): Promise<number> {
231
231
  return await this.aztecNode.getBlockNumber();
232
232
  }
233
+
234
+ public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string> {
235
+ return this.contractDataOracle.getDebugFunctionName(contractAddress, selector);
236
+ }
233
237
  }