@aztec/pxe 0.42.0 → 0.44.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 (58) hide show
  1. package/dest/database/deferred_note_dao.d.ts +5 -4
  2. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  3. package/dest/database/deferred_note_dao.js +4 -3
  4. package/dest/database/incoming_note_dao.d.ts +74 -0
  5. package/dest/database/incoming_note_dao.d.ts.map +1 -0
  6. package/dest/database/incoming_note_dao.js +93 -0
  7. package/dest/database/index.d.ts +1 -0
  8. package/dest/database/index.d.ts.map +1 -1
  9. package/dest/database/index.js +2 -1
  10. package/dest/database/kv_pxe_database.d.ts +10 -7
  11. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  12. package/dest/database/kv_pxe_database.js +149 -78
  13. package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +10 -14
  14. package/dest/database/outgoing_note_dao.d.ts.map +1 -0
  15. package/dest/database/outgoing_note_dao.js +84 -0
  16. package/dest/database/pxe_database.d.ts +21 -9
  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 +71 -24
  20. package/dest/index.d.ts +3 -0
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +4 -1
  23. package/dest/kernel_oracle/index.d.ts +1 -1
  24. package/dest/note_processor/note_processor.d.ts +23 -20
  25. package/dest/note_processor/note_processor.d.ts.map +1 -1
  26. package/dest/note_processor/note_processor.js +116 -76
  27. package/dest/note_processor/produce_note_dao.d.ts +13 -4
  28. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  29. package/dest/note_processor/produce_note_dao.js +88 -31
  30. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
  31. package/dest/pxe_http/pxe_http_server.js +3 -1
  32. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  33. package/dest/pxe_service/create_pxe_service.js +3 -1
  34. package/dest/pxe_service/pxe_service.d.ts +9 -4
  35. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  36. package/dest/pxe_service/pxe_service.js +106 -28
  37. package/dest/simulator_oracle/index.js +2 -2
  38. package/dest/synchronizer/synchronizer.d.ts +2 -2
  39. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  40. package/dest/synchronizer/synchronizer.js +37 -36
  41. package/package.json +23 -15
  42. package/src/database/deferred_note_dao.ts +4 -3
  43. package/src/database/{note_dao.ts → incoming_note_dao.ts} +14 -10
  44. package/src/database/index.ts +1 -0
  45. package/src/database/kv_pxe_database.ts +127 -29
  46. package/src/database/outgoing_note_dao.ts +91 -0
  47. package/src/database/pxe_database.ts +23 -9
  48. package/src/database/pxe_database_test_suite.ts +93 -29
  49. package/src/index.ts +3 -0
  50. package/src/note_processor/note_processor.ts +190 -121
  51. package/src/note_processor/produce_note_dao.ts +164 -50
  52. package/src/pxe_http/pxe_http_server.ts +2 -0
  53. package/src/pxe_service/create_pxe_service.ts +2 -0
  54. package/src/pxe_service/pxe_service.ts +170 -42
  55. package/src/simulator_oracle/index.ts +1 -1
  56. package/src/synchronizer/synchronizer.ts +48 -52
  57. package/dest/database/note_dao.d.ts.map +0 -1
  58. package/dest/database/note_dao.js +0 -89
@@ -3,18 +3,22 @@ import {
3
3
  type AztecNode,
4
4
  EncryptedNoteTxL2Logs,
5
5
  EncryptedTxL2Logs,
6
+ type EventMetadata,
6
7
  ExtendedNote,
7
8
  type FunctionCall,
8
9
  type GetUnencryptedLogsResponse,
10
+ type IncomingNotesFilter,
11
+ L1EventPayload,
9
12
  type L2Block,
10
13
  type LogFilter,
11
14
  MerkleTreeId,
12
- type NoteFilter,
15
+ type OutgoingNotesFilter,
13
16
  type PXE,
14
17
  type PXEInfo,
15
18
  type ProofCreator,
16
19
  SimulatedTx,
17
20
  SimulationError,
21
+ TaggedLog,
18
22
  Tx,
19
23
  type TxEffect,
20
24
  type TxExecutionRequest,
@@ -32,11 +36,11 @@ import {
32
36
  } from '@aztec/circuits.js';
33
37
  import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
34
38
  import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
35
- import { type Fq, Fr } from '@aztec/foundation/fields';
39
+ import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
36
40
  import { SerialQueue } from '@aztec/foundation/fifo';
37
41
  import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
38
42
  import { type KeyStore } from '@aztec/key-store';
39
- import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
43
+ import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
40
44
  import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
41
45
  import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
42
46
  import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
@@ -57,10 +61,11 @@ import { type NodeInfo } from '@aztec/types/interfaces';
57
61
 
58
62
  import { type PXEServiceConfig, getPackageInfo } from '../config/index.js';
59
63
  import { ContractDataOracle } from '../contract_data_oracle/index.js';
64
+ import { IncomingNoteDao } from '../database/incoming_note_dao.js';
60
65
  import { type PxeDatabase } from '../database/index.js';
61
- import { NoteDao } from '../database/note_dao.js';
62
66
  import { KernelOracle } from '../kernel_oracle/index.js';
63
67
  import { KernelProver } from '../kernel_prover/kernel_prover.js';
68
+ import { TestProofCreator } from '../kernel_prover/test/test_circuit_prover.js';
64
69
  import { getAcirSimulator } from '../simulator/index.js';
65
70
  import { Synchronizer } from '../synchronizer/index.js';
66
71
 
@@ -77,6 +82,8 @@ export class PXEService implements PXE {
77
82
  // ensures that state is not changed while simulating
78
83
  private jobQueue = new SerialQueue();
79
84
 
85
+ private fakeProofCreator = new TestProofCreator();
86
+
80
87
  constructor(
81
88
  private keyStore: KeyStore,
82
89
  private node: AztecNode,
@@ -121,11 +128,7 @@ export class PXEService implements PXE {
121
128
  }
122
129
 
123
130
  count++;
124
- this.synchronizer.addAccount(
125
- address.publicKeys.masterIncomingViewingPublicKey,
126
- this.keyStore,
127
- this.config.l2StartingBlock,
128
- );
131
+ await this.synchronizer.addAccount(address.address, this.keyStore, this.config.l2StartingBlock);
129
132
  }
130
133
 
131
134
  if (count > 0) {
@@ -177,6 +180,10 @@ export class PXEService implements PXE {
177
180
  return artifact && getContractClassFromArtifact(artifact);
178
181
  }
179
182
 
183
+ public getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
184
+ return this.db.getContractArtifact(id);
185
+ }
186
+
180
187
  public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
181
188
  const accounts = await this.keyStore.getAccounts();
182
189
  const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress);
@@ -184,10 +191,7 @@ export class PXEService implements PXE {
184
191
  this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
185
192
  return accountCompleteAddress;
186
193
  } else {
187
- const masterIncomingViewingPublicKey = await this.keyStore.getMasterIncomingViewingPublicKey(
188
- accountCompleteAddress.address,
189
- );
190
- this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock);
194
+ await this.synchronizer.addAccount(accountCompleteAddress.address, this.keyStore, this.config.l2StartingBlock);
191
195
  this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
192
196
  this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
193
197
  }
@@ -258,6 +262,7 @@ export class PXEService implements PXE {
258
262
  );
259
263
  }
260
264
  await this.db.addContractArtifact(contractClassId, artifact);
265
+ await this.node.addContractArtifact(instance.address, artifact);
261
266
  } else {
262
267
  // Otherwise, make sure there is an artifact already registered for that class id
263
268
  artifact = await this.db.getContractArtifact(instance.contractClassId);
@@ -284,19 +289,40 @@ export class PXEService implements PXE {
284
289
  return await this.node.getPublicStorageAt(contract, slot);
285
290
  }
286
291
 
287
- public async getNotes(filter: NoteFilter): Promise<ExtendedNote[]> {
288
- const noteDaos = await this.db.getNotes(filter);
292
+ public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
293
+ const noteDaos = await this.db.getIncomingNotes(filter);
289
294
 
290
- // TODO(benesjan): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
291
- // 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
292
297
  const extendedNotes = noteDaos.map(async dao => {
293
298
  let owner = filter.owner;
294
299
  if (owner === undefined) {
295
300
  const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
296
- address.publicKeys.masterIncomingViewingPublicKey.equals(dao.publicKey),
301
+ address.publicKeys.masterIncomingViewingPublicKey.equals(dao.ivpkM),
297
302
  );
298
303
  if (completeAddresses === undefined) {
299
- 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()}`);
300
326
  }
301
327
  owner = completeAddresses.address;
302
328
  }
@@ -317,13 +343,15 @@ export class PXEService implements PXE {
317
343
  }
318
344
 
319
345
  for (const nonce of nonces) {
320
- const { innerNoteHash, siloedNoteHash, innerNullifier } = await this.simulator.computeNoteHashAndNullifier(
321
- note.contractAddress,
322
- nonce,
323
- note.storageSlot,
324
- note.noteTypeId,
325
- note.note,
326
- );
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
+ );
327
355
 
328
356
  const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
329
357
  if (index === undefined) {
@@ -337,7 +365,7 @@ export class PXEService implements PXE {
337
365
  }
338
366
 
339
367
  await this.db.addNote(
340
- new NoteDao(
368
+ new IncomingNoteDao(
341
369
  note.note,
342
370
  note.contractAddress,
343
371
  note.storageSlot,
@@ -353,6 +381,54 @@ export class PXEService implements PXE {
353
381
  }
354
382
  }
355
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
+
356
432
  /**
357
433
  * Finds the nonce(s) for a given note.
358
434
  * @param note - The note to find the nonces for.
@@ -372,11 +448,12 @@ export class PXEService implements PXE {
372
448
  // Remove this once notes added from public also include nonces.
373
449
  {
374
450
  const publicNoteNonce = Fr.ZERO;
375
- const { siloedNoteHash } = await this.simulator.computeNoteHashAndNullifier(
451
+ const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
376
452
  note.contractAddress,
377
453
  publicNoteNonce,
378
454
  note.storageSlot,
379
455
  note.noteTypeId,
456
+ false,
380
457
  note.note,
381
458
  );
382
459
  if (tx.noteHashes.some(hash => hash.equals(siloedNoteHash))) {
@@ -393,11 +470,12 @@ export class PXEService implements PXE {
393
470
  }
394
471
 
395
472
  const nonce = computeNoteHashNonce(firstNullifier, i);
396
- const { siloedNoteHash } = await this.simulator.computeNoteHashAndNullifier(
473
+ const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
397
474
  note.contractAddress,
398
475
  nonce,
399
476
  note.storageSlot,
400
477
  note.noteTypeId,
478
+ false,
401
479
  note.note,
402
480
  );
403
481
  if (hash.equals(siloedNoteHash)) {
@@ -416,8 +494,14 @@ export class PXEService implements PXE {
416
494
  return await this.node.getBlock(blockNumber);
417
495
  }
418
496
 
419
- public async proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean) {
420
- 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
+ });
421
505
  }
422
506
 
423
507
  public async simulateTx(
@@ -426,16 +510,15 @@ export class PXEService implements PXE {
426
510
  msgSender: AztecAddress | undefined = undefined,
427
511
  ): Promise<SimulatedTx> {
428
512
  return await this.jobQueue.put(async () => {
429
- const simulatedTx = await this.#simulateAndProve(txRequest, msgSender);
430
- // We log only if the msgSender is undefined, as simulating with a different msgSender
431
- // is unlikely to be a real transaction, and likely to be only used to read data.
432
- // Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
433
- // If we log, the `getTxHash` function will throw.
434
-
513
+ const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
435
514
  if (simulatePublic) {
436
515
  simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
437
516
  }
438
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.
439
522
  if (!msgSender) {
440
523
  this.log.info(`Executed local simulation for ${simulatedTx.tx.getTxHash()}`);
441
524
  }
@@ -539,7 +622,7 @@ export class PXEService implements PXE {
539
622
  return Promise.resolve({
540
623
  pxeVersion: this.packageVersion,
541
624
  protocolContractAddresses: {
542
- classRegisterer: getCanonicalClassRegistererAddress(),
625
+ classRegisterer: ClassRegistererAddress,
543
626
  gasToken: getCanonicalGasToken().address,
544
627
  instanceDeployer: getCanonicalInstanceDeployer().address,
545
628
  keyRegistry: getCanonicalKeyRegistryAddress(),
@@ -652,18 +735,22 @@ export class PXEService implements PXE {
652
735
  * the function will also include the new contract's public functions in the transaction object.
653
736
  *
654
737
  * @param txExecutionRequest - The transaction request to be simulated and proved.
655
- * @param signature - The ECDSA signature for the transaction request.
738
+ * @param proofCreator - The proof creator to use for proving the execution.
656
739
  * @param msgSender - (Optional) The message sender to use for the simulation.
657
- * @returns An object tract contains:
740
+ * @returns An object that contains:
658
741
  * A private transaction object containing the proof, public inputs, and encrypted logs.
659
742
  * The return values of the private execution
660
743
  */
661
- async #simulateAndProve(txExecutionRequest: TxExecutionRequest, msgSender?: AztecAddress) {
744
+ async #simulateAndProve(
745
+ txExecutionRequest: TxExecutionRequest,
746
+ proofCreator: ProofCreator,
747
+ msgSender?: AztecAddress,
748
+ ): Promise<SimulatedTx> {
662
749
  // Get values that allow us to reconstruct the block hash
663
750
  const executionResult = await this.#simulate(txExecutionRequest, msgSender);
664
751
 
665
752
  const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
666
- const kernelProver = new KernelProver(kernelOracle, this.proofCreator);
753
+ const kernelProver = new KernelProver(kernelOracle, proofCreator);
667
754
  this.log.debug(`Executing kernel prover...`);
668
755
  const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult);
669
756
 
@@ -746,4 +833,45 @@ export class PXEService implements PXE {
746
833
  public async isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
747
834
  return !!(await this.node.getContract(address));
748
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 (!visibleEvent.payload.eventTypeId.equals(eventMetadata.eventSelector)) {
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
+ }
749
877
  }
@@ -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,
@@ -1,4 +1,4 @@
1
- import { type AztecNode, type L2Block, L2BlockL2Logs, MerkleTreeId, type TxHash } from '@aztec/circuit-types';
1
+ import { type AztecNode, type L2Block, MerkleTreeId, type TxHash } from '@aztec/circuit-types';
2
2
  import { type NoteProcessorCaughtUpStats } from '@aztec/circuit-types/stats';
3
3
  import { type AztecAddress, type Fr, INITIAL_L2_BLOCK_NUM, type PublicKey } from '@aztec/circuits.js';
4
4
  import { type SerialQueue } from '@aztec/foundation/fifo';
@@ -7,8 +7,9 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
7
7
  import { type KeyStore } from '@aztec/key-store';
8
8
 
9
9
  import { type DeferredNoteDao } from '../database/deferred_note_dao.js';
10
+ import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
10
11
  import { type PxeDatabase } from '../database/index.js';
11
- import { type NoteDao } from '../database/note_dao.js';
12
+ import { type OutgoingNoteDao } from '../database/outgoing_note_dao.js';
12
13
  import { NoteProcessor } from '../note_processor/index.js';
13
14
 
14
15
  /**
@@ -99,19 +100,13 @@ export class Synchronizer {
99
100
  return false;
100
101
  }
101
102
 
102
- const noteEncryptedLogs = blocks.flatMap(block => block.body.noteEncryptedLogs);
103
-
104
103
  // Update latest tree roots from the most recent block
105
104
  const latestBlock = blocks[blocks.length - 1];
106
105
  await this.setHeaderFromBlock(latestBlock);
107
106
 
108
- const logCount = L2BlockL2Logs.getTotalLogCount(noteEncryptedLogs);
109
- this.log.debug(
110
- `Forwarding ${logCount} encrypted logs and blocks to ${this.noteProcessors.length} note processors`,
111
- );
107
+ this.log.debug(`Forwarding ${blocks.length} blocks to ${this.noteProcessors.length} note processors`);
112
108
  for (const noteProcessor of this.noteProcessors) {
113
- // TODO(#6830): pass in only the blocks
114
- await noteProcessor.process(blocks, noteEncryptedLogs);
109
+ await noteProcessor.process(blocks);
115
110
  }
116
111
  return true;
117
112
  } catch (err) {
@@ -177,11 +172,6 @@ export class Synchronizer {
177
172
  throw new Error('No blocks in processor catch up mode');
178
173
  }
179
174
 
180
- const noteEncryptedLogs = blocks.flatMap(block => block.body.noteEncryptedLogs);
181
-
182
- const logCount = L2BlockL2Logs.getTotalLogCount(noteEncryptedLogs);
183
- this.log.debug(`Forwarding ${logCount} encrypted logs and blocks to note processors in catch up mode`);
184
-
185
175
  for (const noteProcessor of catchUpGroup) {
186
176
  // find the index of the first block that the note processor is not yet synced to
187
177
  const index = blocks.findIndex(block => block.number > noteProcessor.status.syncedToBlock);
@@ -193,27 +183,24 @@ export class Synchronizer {
193
183
  }
194
184
 
195
185
  this.log.debug(
196
- `Catching up note processor ${noteProcessor.masterIncomingViewingPublicKey.toString()} by processing ${
186
+ `Catching up note processor ${noteProcessor.account.toString()} by processing ${
197
187
  blocks.length - index
198
188
  } blocks`,
199
189
  );
200
- await noteProcessor.process(blocks.slice(index), noteEncryptedLogs.slice(index));
190
+ await noteProcessor.process(blocks.slice(index));
201
191
 
202
192
  if (noteProcessor.status.syncedToBlock === toBlockNumber) {
203
193
  // Note processor caught up, move it to `noteProcessors` from `noteProcessorsToCatchUp`.
204
- this.log.debug(
205
- `Note processor for ${noteProcessor.masterIncomingViewingPublicKey.toString()} has caught up`,
206
- {
207
- eventName: 'note-processor-caught-up',
208
- publicKey: noteProcessor.masterIncomingViewingPublicKey.toString(),
209
- duration: noteProcessor.timer.ms(),
210
- dbSize: this.db.estimateSize(),
211
- ...noteProcessor.stats,
212
- } satisfies NoteProcessorCaughtUpStats,
213
- );
194
+ this.log.debug(`Note processor for ${noteProcessor.account.toString()} has caught up`, {
195
+ eventName: 'note-processor-caught-up',
196
+ account: noteProcessor.account.toString(),
197
+ duration: noteProcessor.timer.ms(),
198
+ dbSize: await this.db.estimateSize(),
199
+ ...noteProcessor.stats,
200
+ } satisfies NoteProcessorCaughtUpStats);
214
201
 
215
202
  this.noteProcessorsToCatchUp = this.noteProcessorsToCatchUp.filter(
216
- np => !np.masterIncomingViewingPublicKey.equals(noteProcessor.masterIncomingViewingPublicKey),
203
+ np => !np.account.equals(noteProcessor.account),
217
204
  );
218
205
  this.noteProcessors.push(noteProcessor);
219
206
  }
@@ -257,14 +244,14 @@ export class Synchronizer {
257
244
  * @param startingBlock - The block where to start scanning for notes for this accounts.
258
245
  * @returns A promise that resolves once the account is added to the Synchronizer.
259
246
  */
260
- public addAccount(publicKey: PublicKey, keyStore: KeyStore, startingBlock: number) {
261
- const predicate = (x: NoteProcessor) => x.masterIncomingViewingPublicKey.equals(publicKey);
247
+ public async addAccount(account: AztecAddress, keyStore: KeyStore, startingBlock: number) {
248
+ const predicate = (x: NoteProcessor) => x.account.equals(account);
262
249
  const processor = this.noteProcessors.find(predicate) ?? this.noteProcessorsToCatchUp.find(predicate);
263
250
  if (processor) {
264
251
  return;
265
252
  }
266
253
 
267
- this.noteProcessorsToCatchUp.push(new NoteProcessor(publicKey, keyStore, this.db, this.node, startingBlock));
254
+ this.noteProcessorsToCatchUp.push(await NoteProcessor.create(account, keyStore, this.db, this.node, startingBlock));
268
255
  }
269
256
 
270
257
  /**
@@ -280,9 +267,9 @@ export class Synchronizer {
280
267
  if (!completeAddress) {
281
268
  throw new Error(`Checking if account is synched is not possible for ${account} because it is not registered.`);
282
269
  }
283
- const findByPublicKey = (x: NoteProcessor) =>
284
- x.masterIncomingViewingPublicKey.equals(completeAddress.publicKeys.masterIncomingViewingPublicKey);
285
- const processor = this.noteProcessors.find(findByPublicKey) ?? this.noteProcessorsToCatchUp.find(findByPublicKey);
270
+ const findByAccountAddress = (x: NoteProcessor) => x.account.equals(completeAddress.address);
271
+ const processor =
272
+ this.noteProcessors.find(findByAccountAddress) ?? this.noteProcessorsToCatchUp.find(findByAccountAddress);
286
273
  if (!processor) {
287
274
  throw new Error(
288
275
  `Checking if account is synched is not possible for ${account} because it is only registered as a recipient.`,
@@ -314,9 +301,7 @@ export class Synchronizer {
314
301
  const lastBlockNumber = this.getSynchedBlockNumber();
315
302
  return {
316
303
  blocks: lastBlockNumber,
317
- notes: Object.fromEntries(
318
- this.noteProcessors.map(n => [n.masterIncomingViewingPublicKey.toString(), n.status.syncedToBlock]),
319
- ),
304
+ notes: Object.fromEntries(this.noteProcessors.map(n => [n.account.toString(), n.status.syncedToBlock])),
320
305
  };
321
306
  }
322
307
 
@@ -325,7 +310,7 @@ export class Synchronizer {
325
310
  * @returns The note processor stats for notes for each public key being tracked.
326
311
  */
327
312
  public getSyncStats() {
328
- return Object.fromEntries(this.noteProcessors.map(n => [n.masterIncomingViewingPublicKey.toString(), n.stats]));
313
+ return Object.fromEntries(this.noteProcessors.map(n => [n.account.toString(), n.stats]));
329
314
  }
330
315
 
331
316
  /**
@@ -348,40 +333,51 @@ export class Synchronizer {
348
333
  }
349
334
 
350
335
  // keep track of decoded notes
351
- const newNotes: NoteDao[] = [];
336
+ const incomingNotes: IncomingNoteDao[] = [];
337
+ const outgoingNotes: OutgoingNoteDao[] = [];
338
+
352
339
  // now process each txHash
353
340
  for (const deferredNotes of txHashToDeferredNotes.values()) {
354
341
  // to be safe, try each note processor in case the deferred notes are for different accounts.
355
342
  for (const processor of this.noteProcessors) {
356
- const decodedNotes = await processor.decodeDeferredNotes(
357
- deferredNotes.filter(n => n.publicKey.equals(processor.masterIncomingViewingPublicKey)),
358
- );
359
- newNotes.push(...decodedNotes);
343
+ const { incomingNotes: inNotes, outgoingNotes: outNotes } = await processor.decodeDeferredNotes(deferredNotes);
344
+ incomingNotes.push(...inNotes);
345
+ outgoingNotes.push(...outNotes);
360
346
  }
361
347
  }
362
348
 
363
349
  // now drop the deferred notes, and add the decoded notes
364
350
  await this.db.removeDeferredNotesByContract(contractAddress);
365
- await this.db.addNotes(newNotes);
351
+ await this.db.addNotes(incomingNotes, outgoingNotes);
366
352
 
367
- newNotes.forEach(noteDao => {
353
+ incomingNotes.forEach(noteDao => {
368
354
  this.log.debug(
369
- `Decoded deferred note for contract ${noteDao.contractAddress} at slot ${
355
+ `Decoded deferred incoming note for contract ${noteDao.contractAddress} at slot ${
370
356
  noteDao.storageSlot
371
357
  } with nullifier ${noteDao.siloedNullifier.toString()}`,
372
358
  );
373
359
  });
374
360
 
375
- // now group the decoded notes by public key
376
- const publicKeyToNotes: Map<PublicKey, NoteDao[]> = new Map();
377
- for (const noteDao of newNotes) {
378
- const notesForPublicKey = publicKeyToNotes.get(noteDao.publicKey) ?? [];
361
+ outgoingNotes.forEach(noteDao => {
362
+ this.log.debug(
363
+ `Decoded deferred outgoing note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`,
364
+ );
365
+ });
366
+
367
+ await this.#removeNullifiedNotes(incomingNotes);
368
+ }
369
+
370
+ async #removeNullifiedNotes(notes: IncomingNoteDao[]) {
371
+ // now group the decoded incoming notes by public key
372
+ const publicKeyToIncomingNotes: Map<PublicKey, IncomingNoteDao[]> = new Map();
373
+ for (const noteDao of notes) {
374
+ const notesForPublicKey = publicKeyToIncomingNotes.get(noteDao.ivpkM) ?? [];
379
375
  notesForPublicKey.push(noteDao);
380
- publicKeyToNotes.set(noteDao.publicKey, notesForPublicKey);
376
+ publicKeyToIncomingNotes.set(noteDao.ivpkM, notesForPublicKey);
381
377
  }
382
378
 
383
379
  // now for each group, look for the nullifiers in the nullifier tree
384
- for (const [publicKey, notes] of publicKeyToNotes.entries()) {
380
+ for (const [publicKey, notes] of publicKeyToIncomingNotes.entries()) {
385
381
  const nullifiers = notes.map(n => n.siloedNullifier);
386
382
  const relevantNullifiers: Fr[] = [];
387
383
  for (const nullifier of nullifiers) {
@@ -1 +0,0 @@
1
- {"version":3,"file":"note_dao.d.ts","sourceRoot":"","sources":["../../src/database/note_dao.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,EAAE,EAAS,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;GAEG;AACH,qBAAa,OAAQ,YAAW,QAAQ;IAEpC,kDAAkD;IAC3C,IAAI,EAAE,IAAI;IACjB,oDAAoD;IAC7C,eAAe,EAAE,YAAY;IACpC,iEAAiE;IAC1D,WAAW,EAAE,EAAE;IACtB,iDAAiD;IAC1C,UAAU,EAAE,EAAE;IACrB,kDAAkD;IAC3C,MAAM,EAAE,MAAM;IACrB,6BAA6B;IACtB,KAAK,EAAE,EAAE;IAChB;;;OAGG;IACI,aAAa,EAAE,EAAE;IACxB,8DAA8D;IACvD,eAAe,EAAE,EAAE;IAC1B,+DAA+D;IACxD,KAAK,EAAE,MAAM;IACpB,wDAAwD;IACjD,SAAS,EAAE,SAAS;;IAtB3B,kDAAkD;IAC3C,IAAI,EAAE,IAAI;IACjB,oDAAoD;IAC7C,eAAe,EAAE,YAAY;IACpC,iEAAiE;IAC1D,WAAW,EAAE,EAAE;IACtB,iDAAiD;IAC1C,UAAU,EAAE,EAAE;IACrB,kDAAkD;IAC3C,MAAM,EAAE,MAAM;IACrB,6BAA6B;IACtB,KAAK,EAAE,EAAE;IAChB;;;OAGG;IACI,aAAa,EAAE,EAAE;IACxB,8DAA8D;IACvD,eAAe,EAAE,EAAE;IAC1B,+DAA+D;IACxD,KAAK,EAAE,MAAM;IACpB,wDAAwD;IACjD,SAAS,EAAE,SAAS;IAG7B,QAAQ,IAAI,MAAM;IAclB,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IA4B/C,QAAQ;IAIR,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM;IAK7B;;;OAGG;IACI,OAAO;CAKf"}