@aztec/pxe 0.66.0 → 0.67.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 (93) hide show
  1. package/dest/bin/index.js +5 -6
  2. package/dest/config/index.d.ts +0 -9
  3. package/dest/config/index.d.ts.map +1 -1
  4. package/dest/config/index.js +1 -17
  5. package/dest/config/package_info.d.ts +5 -0
  6. package/dest/config/package_info.d.ts.map +1 -0
  7. package/dest/config/package_info.js +4 -0
  8. package/dest/contract_data_oracle/index.js +2 -2
  9. package/dest/database/incoming_note_dao.d.ts +1 -1
  10. package/dest/database/incoming_note_dao.d.ts.map +1 -1
  11. package/dest/database/incoming_note_dao.js +2 -2
  12. package/dest/database/kv_pxe_database.d.ts +10 -13
  13. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  14. package/dest/database/kv_pxe_database.js +153 -230
  15. package/dest/database/outgoing_note_dao.js +2 -2
  16. package/dest/database/pxe_database.d.ts +7 -25
  17. package/dest/database/pxe_database.d.ts.map +1 -1
  18. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  19. package/dest/database/pxe_database_test_suite.js +18 -59
  20. package/dest/index.d.ts +2 -0
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +3 -1
  23. package/dest/kernel_oracle/index.d.ts.map +1 -1
  24. package/dest/kernel_oracle/index.js +3 -3
  25. package/dest/kernel_prover/index.d.ts +1 -0
  26. package/dest/kernel_prover/index.d.ts.map +1 -1
  27. package/dest/kernel_prover/index.js +2 -1
  28. package/dest/kernel_prover/kernel_prover.d.ts +1 -0
  29. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  30. package/dest/kernel_prover/kernel_prover.js +38 -4
  31. package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
  32. package/dest/kernel_prover/test/test_circuit_prover.js +4 -4
  33. package/dest/note_decryption_utils/add_public_values_to_payload.js +2 -2
  34. package/dest/note_decryption_utils/brute_force_note_info.d.ts +3 -3
  35. package/dest/note_decryption_utils/brute_force_note_info.d.ts.map +1 -1
  36. package/dest/note_decryption_utils/brute_force_note_info.js +8 -8
  37. package/dest/note_decryption_utils/produce_note_daos.d.ts +3 -6
  38. package/dest/note_decryption_utils/produce_note_daos.d.ts.map +1 -1
  39. package/dest/note_decryption_utils/produce_note_daos.js +5 -19
  40. package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +1 -1
  41. package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +1 -1
  42. package/dest/pxe_service/error_enriching.d.ts +3 -3
  43. package/dest/pxe_service/error_enriching.d.ts.map +1 -1
  44. package/dest/pxe_service/error_enriching.js +10 -10
  45. package/dest/pxe_service/index.d.ts +0 -1
  46. package/dest/pxe_service/index.d.ts.map +1 -1
  47. package/dest/pxe_service/index.js +1 -2
  48. package/dest/pxe_service/pxe_service.d.ts +2 -16
  49. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  50. package/dest/pxe_service/pxe_service.js +70 -95
  51. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
  52. package/dest/pxe_service/test/pxe_test_suite.js +1 -3
  53. package/dest/simulator/index.d.ts +1 -1
  54. package/dest/simulator/index.d.ts.map +1 -1
  55. package/dest/simulator/index.js +2 -2
  56. package/dest/simulator_oracle/index.d.ts +7 -6
  57. package/dest/simulator_oracle/index.d.ts.map +1 -1
  58. package/dest/simulator_oracle/index.js +59 -42
  59. package/dest/synchronizer/synchronizer.d.ts +10 -40
  60. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  61. package/dest/synchronizer/synchronizer.js +35 -69
  62. package/dest/{pxe_service → utils}/create_pxe_service.d.ts +1 -1
  63. package/dest/utils/create_pxe_service.d.ts.map +1 -0
  64. package/dest/utils/create_pxe_service.js +49 -0
  65. package/package.json +31 -19
  66. package/src/bin/index.ts +4 -5
  67. package/src/config/index.ts +0 -21
  68. package/src/config/package_info.ts +3 -0
  69. package/src/contract_data_oracle/index.ts +1 -1
  70. package/src/database/incoming_note_dao.ts +2 -2
  71. package/src/database/kv_pxe_database.ts +212 -309
  72. package/src/database/outgoing_note_dao.ts +1 -1
  73. package/src/database/pxe_database.ts +7 -28
  74. package/src/database/pxe_database_test_suite.ts +20 -75
  75. package/src/index.ts +2 -0
  76. package/src/kernel_oracle/index.ts +2 -2
  77. package/src/kernel_prover/index.ts +2 -0
  78. package/src/kernel_prover/kernel_prover.ts +61 -2
  79. package/src/kernel_prover/test/test_circuit_prover.ts +5 -3
  80. package/src/note_decryption_utils/add_public_values_to_payload.ts +1 -1
  81. package/src/note_decryption_utils/brute_force_note_info.ts +9 -9
  82. package/src/note_decryption_utils/produce_note_daos.ts +5 -48
  83. package/src/note_decryption_utils/produce_note_daos_for_key.ts +1 -1
  84. package/src/pxe_service/error_enriching.ts +14 -12
  85. package/src/pxe_service/index.ts +0 -1
  86. package/src/pxe_service/pxe_service.ts +123 -169
  87. package/src/pxe_service/test/pxe_test_suite.ts +0 -3
  88. package/src/simulator/index.ts +1 -1
  89. package/src/simulator_oracle/index.ts +63 -70
  90. package/src/synchronizer/synchronizer.ts +37 -77
  91. package/src/{pxe_service → utils}/create_pxe_service.ts +10 -10
  92. package/dest/pxe_service/create_pxe_service.d.ts.map +0 -1
  93. package/dest/pxe_service/create_pxe_service.js +0 -49
@@ -14,11 +14,11 @@ import {
14
14
  } from '@aztec/circuit-types';
15
15
  import {
16
16
  type AztecAddress,
17
+ type BlockHeader,
17
18
  type CompleteAddress,
18
19
  type ContractInstance,
19
20
  Fr,
20
21
  type FunctionSelector,
21
- type Header,
22
22
  IndexedTaggingSecret,
23
23
  type KeyValidationRequest,
24
24
  type L1_TO_L2_MSG_TREE_HEIGHT,
@@ -28,15 +28,14 @@ import {
28
28
  } from '@aztec/circuits.js';
29
29
  import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi';
30
30
  import { poseidon2Hash } from '@aztec/foundation/crypto';
31
- import { tryJsonStringify } from '@aztec/foundation/json-rpc';
32
- import { createDebugLogger } from '@aztec/foundation/log';
31
+ import { createLogger } from '@aztec/foundation/log';
33
32
  import { type KeyStore } from '@aztec/key-store';
34
- import { type AcirSimulator, type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator';
33
+ import { MessageLoadOracleInputs } from '@aztec/simulator/acvm';
34
+ import { type AcirSimulator, type DBOracle } from '@aztec/simulator/client';
35
35
 
36
36
  import { type ContractDataOracle } from '../contract_data_oracle/index.js';
37
37
  import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
38
38
  import { type PxeDatabase } from '../database/index.js';
39
- import { type OutgoingNoteDao } from '../database/outgoing_note_dao.js';
40
39
  import { produceNoteDaos } from '../note_decryption_utils/produce_note_daos.js';
41
40
  import { getAcirSimulator } from '../simulator/index.js';
42
41
 
@@ -49,7 +48,7 @@ export class SimulatorOracle implements DBOracle {
49
48
  private db: PxeDatabase,
50
49
  private keyStore: KeyStore,
51
50
  private aztecNode: AztecNode,
52
- private log = createDebugLogger('aztec:pxe:simulator_oracle'),
51
+ private log = createLogger('pxe:simulator_oracle'),
53
52
  ) {}
54
53
 
55
54
  getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise<KeyValidationRequest> {
@@ -229,10 +228,10 @@ export class SimulatorOracle implements DBOracle {
229
228
  * Retrieve the databases view of the Block Header object.
230
229
  * This structure is fed into the circuits simulator and is used to prove against certain historical roots.
231
230
  *
232
- * @returns A Promise that resolves to a Header object.
231
+ * @returns A Promise that resolves to a BlockHeader object.
233
232
  */
234
- getHeader(): Promise<Header> {
235
- return Promise.resolve(this.db.getHeader());
233
+ getBlockHeader(): Promise<BlockHeader> {
234
+ return this.db.getBlockHeader();
236
235
  }
237
236
 
238
237
  /**
@@ -253,7 +252,7 @@ export class SimulatorOracle implements DBOracle {
253
252
  * finally the index specified tag. We will then query the node with this tag for each address in the address book.
254
253
  * @returns The full list of the users contact addresses.
255
254
  */
256
- public getContacts(): AztecAddress[] {
255
+ public getContacts(): Promise<AztecAddress[]> {
257
256
  return this.db.getContactAddresses();
258
257
  }
259
258
 
@@ -291,9 +290,13 @@ export class SimulatorOracle implements DBOracle {
291
290
  ): Promise<void> {
292
291
  const secret = await this.#calculateTaggingSecret(contractAddress, sender, recipient);
293
292
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
294
- this.log.verbose(
295
- `Incrementing secret ${secret} as sender ${sender} for recipient: ${recipient} at contract: ${contractName}(${contractAddress})`,
296
- );
293
+ this.log.debug(`Incrementing app tagging secret at ${contractName}(${contractAddress})`, {
294
+ secret,
295
+ sender,
296
+ recipient,
297
+ contractName,
298
+ contractAddress,
299
+ });
297
300
 
298
301
  const [index] = await this.db.getTaggingSecretsIndexesAsSender([secret]);
299
302
  await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index + 1)]);
@@ -325,7 +328,7 @@ export class SimulatorOracle implements DBOracle {
325
328
  const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
326
329
 
327
330
  // We implicitly add all PXE accounts as contacts, this helps us decrypt tags on notes that we send to ourselves (recipient = us, sender = us)
328
- const contacts = [...this.db.getContactAddresses(), ...(await this.keyStore.getAccounts())].filter(
331
+ const contacts = [...(await this.db.getContactAddresses()), ...(await this.keyStore.getAccounts())].filter(
329
332
  (address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)),
330
333
  );
331
334
  const appTaggingSecrets = contacts.map(contact => {
@@ -395,13 +398,17 @@ export class SimulatorOracle implements DBOracle {
395
398
  await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, newIndex)]);
396
399
 
397
400
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
398
- this.log.debug(
399
- `Syncing logs for sender ${sender}, secret ${appTaggingSecret}:${currentIndex} at contract: ${contractName}(${contractAddress})`,
400
- );
401
+ this.log.debug(`Syncing logs for sender ${sender} at contract ${contractName}(${contractAddress})`, {
402
+ sender,
403
+ secret: appTaggingSecret,
404
+ index: currentIndex,
405
+ contractName,
406
+ contractAddress,
407
+ });
401
408
  }
402
409
 
403
410
  /**
404
- * Synchronizes the logs tagged with scoped addresses and all the senders in the addressbook.
411
+ * Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
405
412
  * Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs to sync.
406
413
  * @param contractAddress - The address of the contract that the logs are tagged for
407
414
  * @param recipient - The address of the recipient
@@ -427,7 +434,7 @@ export class SimulatorOracle implements DBOracle {
427
434
  const appTaggingSecrets = await this.#getAppTaggingSecretsForContacts(contractAddress, recipient);
428
435
 
429
436
  // 1.1 Set up a sliding window with an offset. Chances are the sender might have messed up
430
- // and inadvertedly incremented their index without use getting any logs (for example, in case
437
+ // and inadvertently incremented their index without use getting any logs (for example, in case
431
438
  // of a revert). If we stopped looking for logs the first time
432
439
  // we receive 0 for a tag, we might never receive anything from that sender again.
433
440
  // Also there's a possibility that we have advanced our index, but the sender has reused it, so
@@ -475,24 +482,32 @@ export class SimulatorOracle implements DBOracle {
475
482
  logsByTags.forEach((logsByTag, logIndex) => {
476
483
  const { secret: currentSecret, index: currentIndex } = currentTagggingSecrets[logIndex];
477
484
  const currentSecretAsStr = currentSecret.toString();
478
- this.log.debug(
479
- `Syncing logs for recipient ${recipient}, secret ${currentSecretAsStr}:${currentIndex} at contract: ${contractName}(${contractAddress})`,
480
- );
485
+ this.log.debug(`Syncing logs for recipient ${recipient} at contract ${contractName}(${contractAddress})`, {
486
+ recipient,
487
+ secret: currentSecret,
488
+ index: currentIndex,
489
+ contractName,
490
+ contractAddress,
491
+ });
481
492
  // 3.1. Append logs to the list and increment the index for the tags that have logs (#9380)
482
493
  if (logsByTag.length > 0) {
483
- this.log.verbose(
484
- `Found ${
485
- logsByTag.length
486
- } logs for secret ${currentSecretAsStr} as recipient ${recipient}. Incrementing index to ${
487
- currentIndex + 1
488
- } at contract: ${contractName}(${contractAddress})`,
494
+ const newIndex = currentIndex + 1;
495
+ this.log.debug(
496
+ `Found ${logsByTag.length} logs as recipient ${recipient}. Incrementing index to ${newIndex} at contract ${contractName}(${contractAddress})`,
497
+ {
498
+ recipient,
499
+ secret: currentSecret,
500
+ newIndex,
501
+ contractName,
502
+ contractAddress,
503
+ },
489
504
  );
490
505
  logs.push(...logsByTag);
491
506
 
492
507
  if (currentIndex >= initialSecretIndexes[currentSecretAsStr]) {
493
508
  // 3.2. Increment the index for the tags that have logs, provided they're higher than the one
494
509
  // we have stored in the db (#9380)
495
- secretsToIncrement[currentSecretAsStr] = currentIndex + 1;
510
+ secretsToIncrement[currentSecretAsStr] = newIndex;
496
511
  // 3.3. Slide the window forwards if we have found logs beyond the initial index
497
512
  maxIndexesToCheck[currentSecretAsStr] = currentIndex + INDEX_OFFSET;
498
513
  }
@@ -506,7 +521,7 @@ export class SimulatorOracle implements DBOracle {
506
521
  });
507
522
  await this.db.setTaggingSecretsIndexesAsRecipient(
508
523
  Object.keys(secretsToIncrement).map(
509
- secret => new IndexedTaggingSecret(Fr.fromString(secret), secretsToIncrement[secret]),
524
+ secret => new IndexedTaggingSecret(Fr.fromHexString(secret), secretsToIncrement[secret]),
510
525
  ),
511
526
  );
512
527
  currentTagggingSecrets = newTaggingSecrets;
@@ -538,14 +553,11 @@ export class SimulatorOracle implements DBOracle {
538
553
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
539
554
  );
540
555
  const addressSecret = computeAddressSecret(recipientCompleteAddress.getPreaddress(), ivskM);
541
- const ovskM = await this.keyStore.getMasterSecretKey(
542
- recipientCompleteAddress.publicKeys.masterOutgoingViewingPublicKey,
543
- );
556
+
544
557
  // Since we could have notes with the same index for different txs, we need
545
558
  // to keep track of them scoping by txHash
546
559
  const excludedIndices: Map<string, Set<number>> = new Map();
547
560
  const incomingNotes: IncomingNoteDao[] = [];
548
- const outgoingNotes: OutgoingNoteDao[] = [];
549
561
 
550
562
  const txEffectsCache = new Map<string, InBlock<TxEffect> | undefined>();
551
563
 
@@ -553,21 +565,9 @@ export class SimulatorOracle implements DBOracle {
553
565
  const incomingNotePayload = scopedLog.isFromPublic
554
566
  ? L1NotePayload.decryptAsIncomingFromPublic(scopedLog.logData, addressSecret)
555
567
  : L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
556
- const outgoingNotePayload = scopedLog.isFromPublic
557
- ? L1NotePayload.decryptAsOutgoingFromPublic(scopedLog.logData, ovskM)
558
- : L1NotePayload.decryptAsOutgoing(PrivateLog.fromBuffer(scopedLog.logData), ovskM);
559
-
560
- if (incomingNotePayload || outgoingNotePayload) {
561
- if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
562
- this.log.warn(
563
- `Incoming and outgoing note payloads do not match. Incoming: ${tryJsonStringify(
564
- incomingNotePayload,
565
- )}, Outgoing: ${tryJsonStringify(outgoingNotePayload)}`,
566
- );
567
- continue;
568
- }
569
568
 
570
- const payload = incomingNotePayload || outgoingNotePayload;
569
+ if (incomingNotePayload) {
570
+ const payload = incomingNotePayload;
571
571
 
572
572
  const txEffect =
573
573
  txEffectsCache.get(scopedLog.txHash.toString()) ?? (await this.aztecNode.getTxEffect(scopedLog.txHash));
@@ -582,14 +582,13 @@ export class SimulatorOracle implements DBOracle {
582
582
  if (!excludedIndices.has(scopedLog.txHash.toString())) {
583
583
  excludedIndices.set(scopedLog.txHash.toString(), new Set());
584
584
  }
585
- const { incomingNote, outgoingNote } = await produceNoteDaos(
585
+ const { incomingNote } = await produceNoteDaos(
586
586
  // I don't like this at all, but we need a simulator to run `computeNoteHashAndOptionallyANullifier`. This generates
587
587
  // a chicken-and-egg problem due to this oracle requiring a simulator, which in turn requires this oracle. Furthermore, since jest doesn't allow
588
588
  // mocking ESM exports, we have to pollute the method even more by providing a simulator parameter so tests can inject a fake one.
589
589
  simulator ?? getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.contractDataOracle),
590
590
  this.db,
591
591
  incomingNotePayload ? recipient.toAddressPoint() : undefined,
592
- outgoingNotePayload ? recipientCompleteAddress.publicKeys.masterOutgoingViewingPublicKey : undefined,
593
592
  payload!,
594
593
  txEffect.data.txHash,
595
594
  txEffect.l2BlockNumber,
@@ -603,12 +602,9 @@ export class SimulatorOracle implements DBOracle {
603
602
  if (incomingNote) {
604
603
  incomingNotes.push(incomingNote);
605
604
  }
606
- if (outgoingNote) {
607
- outgoingNotes.push(outgoingNote);
608
- }
609
605
  }
610
606
  }
611
- return { incomingNotes, outgoingNotes };
607
+ return { incomingNotes };
612
608
  }
613
609
 
614
610
  /**
@@ -621,18 +617,15 @@ export class SimulatorOracle implements DBOracle {
621
617
  recipient: AztecAddress,
622
618
  simulator?: AcirSimulator,
623
619
  ): Promise<void> {
624
- const { incomingNotes, outgoingNotes } = await this.#decryptTaggedLogs(logs, recipient, simulator);
625
- if (incomingNotes.length || outgoingNotes.length) {
626
- await this.db.addNotes(incomingNotes, outgoingNotes, recipient);
620
+ const { incomingNotes } = await this.#decryptTaggedLogs(logs, recipient, simulator);
621
+ if (incomingNotes.length) {
622
+ await this.db.addNotes(incomingNotes, recipient);
627
623
  incomingNotes.forEach(noteDao => {
628
- this.log.verbose(
629
- `Added incoming note for contract ${noteDao.contractAddress} at slot ${
630
- noteDao.storageSlot
631
- } with nullifier ${noteDao.siloedNullifier.toString()}`,
632
- );
633
- });
634
- outgoingNotes.forEach(noteDao => {
635
- this.log.verbose(`Added outgoing note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`);
624
+ this.log.verbose(`Added incoming note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
625
+ contract: noteDao.contractAddress,
626
+ slot: noteDao.storageSlot,
627
+ nullifier: noteDao.siloedNullifier.toString(),
628
+ });
636
629
  });
637
630
  }
638
631
  const nullifiedNotes: IncomingNoteDao[] = [];
@@ -651,11 +644,11 @@ export class SimulatorOracle implements DBOracle {
651
644
 
652
645
  await this.db.removeNullifiedNotes(foundNullifiers, recipient.toAddressPoint());
653
646
  nullifiedNotes.forEach(noteDao => {
654
- this.log.verbose(
655
- `Removed note for contract ${noteDao.contractAddress} at slot ${
656
- noteDao.storageSlot
657
- } with nullifier ${noteDao.siloedNullifier.toString()}`,
658
- );
647
+ this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
648
+ contract: noteDao.contractAddress,
649
+ slot: noteDao.storageSlot,
650
+ nullifier: noteDao.siloedNullifier.toString(),
651
+ });
659
652
  });
660
653
  }
661
654
  }
@@ -5,39 +5,36 @@ import {
5
5
  type L2BlockStreamEventHandler,
6
6
  } from '@aztec/circuit-types';
7
7
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js';
8
- import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
8
+ import { type Logger, createLogger } from '@aztec/foundation/log';
9
9
  import { type L2TipsStore } from '@aztec/kv-store/stores';
10
10
 
11
11
  import { type PXEConfig } from '../config/index.js';
12
12
  import { type PxeDatabase } from '../database/index.js';
13
13
 
14
14
  /**
15
- * The Synchronizer class manages the synchronization of note processors and interacts with the Aztec node
16
- * to obtain encrypted logs, blocks, and other necessary information for the accounts.
17
- * It provides methods to start or stop the synchronization process, add new accounts, retrieve account
18
- * details, and fetch transactions by hash. The Synchronizer ensures that it maintains the note processors
19
- * in sync with the blockchain while handling retries and errors gracefully.
15
+ * The Synchronizer class manages the synchronization with the aztec node, allowing PXE to retrieve the
16
+ * latest block header and handle reorgs.
17
+ * It provides methods to trigger a sync and get the block number we are syncec to
18
+ * details, and fetch transactions by hash.
20
19
  */
21
20
  export class Synchronizer implements L2BlockStreamEventHandler {
22
- private running = false;
23
21
  private initialSyncBlockNumber = INITIAL_L2_BLOCK_NUM - 1;
24
- private log: DebugLogger;
22
+ private log: Logger;
25
23
  protected readonly blockStream: L2BlockStream;
26
24
 
27
25
  constructor(
28
26
  private node: AztecNode,
29
27
  private db: PxeDatabase,
30
28
  private l2TipsStore: L2TipsStore,
31
- config: Partial<Pick<PXEConfig, 'l2BlockPollingIntervalMS' | 'l2StartingBlock'>> = {},
29
+ config: Partial<Pick<PXEConfig, 'l2StartingBlock'>> = {},
32
30
  logSuffix?: string,
33
31
  ) {
34
- this.log = createDebugLogger(logSuffix ? `aztec:pxe_synchronizer_${logSuffix}` : 'aztec:pxe_synchronizer');
32
+ this.log = createLogger(logSuffix ? `pxe:synchronizer:${logSuffix}` : 'pxe:synchronizer');
35
33
  this.blockStream = this.createBlockStream(config);
36
34
  }
37
35
 
38
- protected createBlockStream(config: Partial<Pick<PXEConfig, 'l2BlockPollingIntervalMS' | 'l2StartingBlock'>>) {
39
- return new L2BlockStream(this.node, this.l2TipsStore, this, {
40
- pollIntervalMS: config.l2BlockPollingIntervalMS,
36
+ protected createBlockStream(config: Partial<Pick<PXEConfig, 'l2StartingBlock'>>) {
37
+ return new L2BlockStream(this.node, this.l2TipsStore, this, createLogger('pxe:block_stream'), {
41
38
  startingBlock: config.l2StartingBlock,
42
39
  });
43
40
  }
@@ -47,12 +44,18 @@ export class Synchronizer implements L2BlockStreamEventHandler {
47
44
  await this.l2TipsStore.handleBlockStreamEvent(event);
48
45
 
49
46
  switch (event.type) {
50
- case 'blocks-added':
51
- this.log.verbose(`Processing blocks ${event.blocks[0].number} to ${event.blocks.at(-1)!.number}`);
52
- await this.db.setHeader(event.blocks.at(-1)!.header);
47
+ case 'blocks-added': {
48
+ const lastBlock = event.blocks.at(-1)!;
49
+ this.log.verbose(`Updated pxe last block to ${lastBlock.number}`, {
50
+ blockHash: lastBlock.hash(),
51
+ archive: lastBlock.archive.root.toString(),
52
+ header: lastBlock.header.toInspect(),
53
+ });
54
+ await this.db.setHeader(lastBlock.header);
53
55
  break;
54
- case 'chain-pruned':
55
- this.log.info(`Pruning data after block ${event.blockNumber} due to reorg`);
56
+ }
57
+ case 'chain-pruned': {
58
+ this.log.warn(`Pruning data after block ${event.blockNumber} due to reorg`);
56
59
  // We first unnullify and then remove so that unnullified notes that were created after the block number end up deleted.
57
60
  await this.db.unnullifyNotesAfter(event.blockNumber);
58
61
  await this.db.removeNotesAfter(event.blockNumber);
@@ -62,73 +65,30 @@ export class Synchronizer implements L2BlockStreamEventHandler {
62
65
  // Update the header to the last block.
63
66
  await this.db.setHeader(await this.node.getBlockHeader(event.blockNumber));
64
67
  break;
68
+ }
65
69
  }
66
70
  }
67
71
 
68
72
  /**
69
- * Starts the synchronization process by fetching encrypted logs and blocks from a specified position.
70
- * Continuously processes the fetched data for all note processors until stopped. If there is no data
71
- * available, it retries after a specified interval.
72
- *
73
- * @param limit - The maximum number of encrypted, unencrypted logs and blocks to fetch in each iteration.
74
- * @param retryInterval - The time interval (in ms) to wait before retrying if no data is available.
73
+ * Syncs PXE and the node by dowloading the metadata of the latest blocks, allowing simulations to use
74
+ * recent data (e.g. notes), and handling any reorgs that might have occurred.
75
75
  */
76
- public async start() {
77
- if (this.running) {
78
- return;
79
- }
80
- this.running = true;
81
-
82
- // REFACTOR: We should know the header of the genesis block without having to request it from the node.
83
- await this.db.setHeader(await this.node.getBlockHeader(0));
76
+ public async sync() {
77
+ let currentHeader;
84
78
 
85
- await this.trigger();
86
- this.log.info('Initial sync complete');
87
- this.blockStream.start();
88
- this.log.debug('Started loop');
89
- }
90
-
91
- /**
92
- * Stops the synchronizer gracefully, interrupting any ongoing sleep and waiting for the current
93
- * iteration to complete before setting the running state to false. Once stopped, the synchronizer
94
- * will no longer process blocks or encrypted logs and must be restarted using the start method.
95
- *
96
- * @returns A promise that resolves when the synchronizer has successfully stopped.
97
- */
98
- public async stop() {
99
- this.running = false;
100
- await this.blockStream.stop();
101
- this.log.info('Stopped');
102
- }
103
-
104
- /** Triggers a single run. */
105
- public async trigger() {
79
+ try {
80
+ currentHeader = await this.db.getBlockHeader();
81
+ } catch (e) {
82
+ this.log.debug('Header is not set, requesting from the node');
83
+ }
84
+ if (!currentHeader) {
85
+ // REFACTOR: We should know the header of the genesis block without having to request it from the node.
86
+ await this.db.setHeader(await this.node.getBlockHeader(0));
87
+ }
106
88
  await this.blockStream.sync();
107
89
  }
108
90
 
109
- private getSynchedBlockNumber() {
110
- return this.db.getBlockNumber() ?? this.initialSyncBlockNumber;
111
- }
112
-
113
- /**
114
- * Checks whether all the blocks were processed (tree roots updated, txs updated with block info, etc.).
115
- * @returns True if there are no outstanding blocks to be synched.
116
- * @remarks This indicates that blocks and transactions are synched even if notes are not.
117
- * @remarks Compares local block number with the block number from aztec node.
118
- */
119
- public async isGlobalStateSynchronized() {
120
- const latest = await this.node.getBlockNumber();
121
- return latest <= this.getSynchedBlockNumber();
122
- }
123
-
124
- /**
125
- * Returns the latest block that has been synchronized by the synchronizer and each account.
126
- * @returns The latest block synchronized for blocks, and the latest block synched for notes for each public key being tracked.
127
- */
128
- public getSyncStatus() {
129
- const lastBlockNumber = this.getSynchedBlockNumber();
130
- return {
131
- blocks: lastBlockNumber,
132
- };
91
+ public async getSynchedBlockNumber() {
92
+ return (await this.db.getBlockNumber()) ?? this.initialSyncBlockNumber;
133
93
  }
134
94
  }
@@ -1,15 +1,15 @@
1
1
  import { BBNativePrivateKernelProver } from '@aztec/bb-prover';
2
2
  import { type AztecNode, type PrivateKernelProver } from '@aztec/circuit-types';
3
3
  import { randomBytes } from '@aztec/foundation/crypto';
4
- import { createDebugLogger } from '@aztec/foundation/log';
4
+ import { createLogger } from '@aztec/foundation/log';
5
5
  import { KeyStore } from '@aztec/key-store';
6
+ import { createStore } from '@aztec/kv-store/lmdb';
6
7
  import { L2TipsStore } from '@aztec/kv-store/stores';
7
- import { createStore } from '@aztec/kv-store/utils';
8
8
 
9
9
  import { type PXEServiceConfig } from '../config/index.js';
10
10
  import { KVPxeDatabase } from '../database/kv_pxe_database.js';
11
11
  import { TestPrivateKernelProver } from '../kernel_prover/test/test_circuit_prover.js';
12
- import { PXEService } from './pxe_service.js';
12
+ import { PXEService } from '../pxe_service/pxe_service.js';
13
13
 
14
14
  /**
15
15
  * Create and start an PXEService instance with the given AztecNode.
@@ -38,18 +38,18 @@ export async function createPXEService(
38
38
  } as PXEServiceConfig;
39
39
 
40
40
  const keyStore = new KeyStore(
41
- await createStore('pxe_key_store', configWithContracts, createDebugLogger('aztec:pxe:keystore:lmdb')),
41
+ await createStore('pxe_key_store', configWithContracts, createLogger('pxe:keystore:lmdb')),
42
42
  );
43
43
 
44
- const store = await createStore('pxe_data', configWithContracts, createDebugLogger('aztec:pxe:data:lmdb'));
44
+ const store = await createStore('pxe_data', configWithContracts, createLogger('pxe:data:lmdb'));
45
45
 
46
- const db = new KVPxeDatabase(store);
46
+ const db = await KVPxeDatabase.create(store);
47
47
  const tips = new L2TipsStore(store, 'pxe');
48
48
 
49
49
  const prover = proofCreator ?? (await createProver(config, logSuffix));
50
- const server = new PXEService(keyStore, aztecNode, db, tips, prover, config, logSuffix);
51
- await server.start();
52
- return server;
50
+ const pxe = new PXEService(keyStore, aztecNode, db, tips, prover, config, logSuffix);
51
+ await pxe.init();
52
+ return pxe;
53
53
  }
54
54
 
55
55
  function createProver(config: PXEServiceConfig, logSuffix?: string) {
@@ -62,6 +62,6 @@ function createProver(config: PXEServiceConfig, logSuffix?: string) {
62
62
  throw new Error(`Prover must be configured with binary path and working directory`);
63
63
  }
64
64
  const bbConfig = config as Required<Pick<PXEServiceConfig, 'bbBinaryPath' | 'bbWorkingDirectory'>> & PXEServiceConfig;
65
- const log = createDebugLogger('aztec:pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
65
+ const log = createLogger('pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
66
66
  return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, log);
67
67
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"create_pxe_service.d.ts","sourceRoot":"","sources":["../../src/pxe_service/create_pxe_service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAOhF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,gBAAgB,EACxB,YAAY,GAAE,MAAM,GAAG,OAAO,GAAG,SAAqB,EACtD,YAAY,CAAC,EAAE,mBAAmB,uBAwBnC"}
@@ -1,49 +0,0 @@
1
- import { BBNativePrivateKernelProver } from '@aztec/bb-prover';
2
- import { randomBytes } from '@aztec/foundation/crypto';
3
- import { createDebugLogger } from '@aztec/foundation/log';
4
- import { KeyStore } from '@aztec/key-store';
5
- import { L2TipsStore } from '@aztec/kv-store/stores';
6
- import { createStore } from '@aztec/kv-store/utils';
7
- import { KVPxeDatabase } from '../database/kv_pxe_database.js';
8
- import { TestPrivateKernelProver } from '../kernel_prover/test/test_circuit_prover.js';
9
- import { PXEService } from './pxe_service.js';
10
- /**
11
- * Create and start an PXEService instance with the given AztecNode.
12
- * If no keyStore or database is provided, it will use KeyStore and MemoryDB as default values.
13
- * Returns a Promise that resolves to the started PXEService instance.
14
- *
15
- * @param aztecNode - The AztecNode instance to be used by the server.
16
- * @param config - The PXE Service Config to use
17
- * @param options - (Optional) Optional information for creating an PXEService.
18
- * @param proofCreator - An optional proof creator to use in place of any other configuration
19
- * @returns A Promise that resolves to the started PXEService instance.
20
- */
21
- export async function createPXEService(aztecNode, config, useLogSuffix = undefined, proofCreator) {
22
- const logSuffix = typeof useLogSuffix === 'boolean' ? (useLogSuffix ? randomBytes(3).toString('hex') : undefined) : useLogSuffix;
23
- const l1Contracts = await aztecNode.getL1ContractAddresses();
24
- const configWithContracts = {
25
- ...config,
26
- l1Contracts,
27
- };
28
- const keyStore = new KeyStore(await createStore('pxe_key_store', configWithContracts, createDebugLogger('aztec:pxe:keystore:lmdb')));
29
- const store = await createStore('pxe_data', configWithContracts, createDebugLogger('aztec:pxe:data:lmdb'));
30
- const db = new KVPxeDatabase(store);
31
- const tips = new L2TipsStore(store, 'pxe');
32
- const prover = proofCreator ?? (await createProver(config, logSuffix));
33
- const server = new PXEService(keyStore, aztecNode, db, tips, prover, config, logSuffix);
34
- await server.start();
35
- return server;
36
- }
37
- function createProver(config, logSuffix) {
38
- if (!config.proverEnabled) {
39
- return new TestPrivateKernelProver();
40
- }
41
- // (@PhilWindle) Temporary validation until WASM is implemented
42
- if (!config.bbBinaryPath || !config.bbWorkingDirectory) {
43
- throw new Error(`Prover must be configured with binary path and working directory`);
44
- }
45
- const bbConfig = config;
46
- const log = createDebugLogger('aztec:pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
47
- return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, log);
48
- }
49
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX3B4ZV9zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3B4ZV9zZXJ2aWNlL2NyZWF0ZV9weGVfc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUUvRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHcEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQy9ELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBQ3ZGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU5Qzs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxnQkFBZ0IsQ0FDcEMsU0FBb0IsRUFDcEIsTUFBd0IsRUFDeEIsZUFBNkMsU0FBUyxFQUN0RCxZQUFrQztJQUVsQyxNQUFNLFNBQVMsR0FDYixPQUFPLFlBQVksS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO0lBRWpILE1BQU0sV0FBVyxHQUFHLE1BQU0sU0FBUyxDQUFDLHNCQUFzQixFQUFFLENBQUM7SUFDN0QsTUFBTSxtQkFBbUIsR0FBRztRQUMxQixHQUFHLE1BQU07UUFDVCxXQUFXO0tBQ1EsQ0FBQztJQUV0QixNQUFNLFFBQVEsR0FBRyxJQUFJLFFBQVEsQ0FDM0IsTUFBTSxXQUFXLENBQUMsZUFBZSxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixDQUFDLHlCQUF5QixDQUFDLENBQUMsQ0FDdEcsQ0FBQztJQUVGLE1BQU0sS0FBSyxHQUFHLE1BQU0sV0FBVyxDQUFDLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUM7SUFFM0csTUFBTSxFQUFFLEdBQUcsSUFBSSxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxXQUFXLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRTNDLE1BQU0sTUFBTSxHQUFHLFlBQVksSUFBSSxDQUFDLE1BQU0sWUFBWSxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3ZFLE1BQU0sTUFBTSxHQUFHLElBQUksVUFBVSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ3hGLE1BQU0sTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JCLE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLFlBQVksQ0FBQyxNQUF3QixFQUFFLFNBQWtCO0lBQ2hFLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDMUIsT0FBTyxJQUFJLHVCQUF1QixFQUFFLENBQUM7SUFDdkMsQ0FBQztJQUVELCtEQUErRDtJQUMvRCxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQUMsa0VBQWtFLENBQUMsQ0FBQztJQUN0RixDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQUcsTUFBb0csQ0FBQztJQUN0SCxNQUFNLEdBQUcsR0FBRyxpQkFBaUIsQ0FBQyw0QkFBNEIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNqRyxPQUFPLDJCQUEyQixDQUFDLEdBQUcsQ0FBQyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsR0FBRyxRQUFRLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUNyRixDQUFDIn0=