@aztec/pxe 0.60.0 → 0.61.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 (54) hide show
  1. package/dest/database/deferred_note_dao.d.ts +6 -19
  2. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  3. package/dest/database/deferred_note_dao.js +8 -18
  4. package/dest/database/incoming_note_dao.d.ts +1 -1
  5. package/dest/database/incoming_note_dao.d.ts.map +1 -1
  6. package/dest/database/incoming_note_dao.js +3 -3
  7. package/dest/database/kv_pxe_database.d.ts +5 -3
  8. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  9. package/dest/database/kv_pxe_database.js +22 -8
  10. package/dest/database/outgoing_note_dao.d.ts +1 -1
  11. package/dest/database/outgoing_note_dao.d.ts.map +1 -1
  12. package/dest/database/outgoing_note_dao.js +3 -3
  13. package/dest/database/pxe_database.d.ts +6 -4
  14. package/dest/database/pxe_database.d.ts.map +1 -1
  15. package/dest/note_processor/note_processor.d.ts +1 -5
  16. package/dest/note_processor/note_processor.d.ts.map +1 -1
  17. package/dest/note_processor/note_processor.js +56 -58
  18. package/dest/note_processor/utils/add_public_values_to_payload.d.ts +10 -0
  19. package/dest/note_processor/utils/add_public_values_to_payload.d.ts.map +1 -0
  20. package/dest/note_processor/utils/add_public_values_to_payload.js +48 -0
  21. package/dest/note_processor/utils/brute_force_note_info.d.ts +8 -3
  22. package/dest/note_processor/utils/brute_force_note_info.d.ts.map +1 -1
  23. package/dest/note_processor/utils/brute_force_note_info.js +6 -3
  24. package/dest/note_processor/utils/produce_note_daos.d.ts.map +1 -1
  25. package/dest/note_processor/utils/produce_note_daos.js +2 -4
  26. package/dest/note_processor/utils/produce_note_daos_for_key.d.ts +3 -3
  27. package/dest/note_processor/utils/produce_note_daos_for_key.d.ts.map +1 -1
  28. package/dest/note_processor/utils/produce_note_daos_for_key.js +7 -61
  29. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  30. package/dest/pxe_service/pxe_service.js +20 -6
  31. package/dest/simulator_oracle/index.d.ts +17 -1
  32. package/dest/simulator_oracle/index.d.ts.map +1 -1
  33. package/dest/simulator_oracle/index.js +40 -1
  34. package/dest/synchronizer/synchronizer.d.ts +1 -1
  35. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  36. package/dest/synchronizer/synchronizer.js +3 -3
  37. package/package.json +14 -14
  38. package/src/database/deferred_note_dao.ts +6 -19
  39. package/src/database/incoming_note_dao.ts +2 -1
  40. package/src/database/kv_pxe_database.ts +26 -6
  41. package/src/database/outgoing_note_dao.ts +2 -1
  42. package/src/database/pxe_database.ts +8 -4
  43. package/src/note_processor/note_processor.ts +89 -88
  44. package/src/note_processor/utils/add_public_values_to_payload.ts +63 -0
  45. package/src/note_processor/utils/brute_force_note_info.ts +11 -3
  46. package/src/note_processor/utils/produce_note_daos.ts +5 -7
  47. package/src/note_processor/utils/produce_note_daos_for_key.ts +19 -114
  48. package/src/pxe_service/pxe_service.ts +22 -3
  49. package/src/simulator_oracle/index.ts +51 -0
  50. package/src/synchronizer/synchronizer.ts +2 -2
  51. package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts +0 -12
  52. package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts.map +0 -1
  53. package/dest/note_processor/utils/add_nullable_field_to_payload.js +0 -46
  54. package/src/note_processor/utils/add_nullable_field_to_payload.ts +0 -67
@@ -14,7 +14,7 @@ import {
14
14
  } from '@aztec/circuits.js';
15
15
  import { type ContractArtifact } from '@aztec/foundation/abi';
16
16
  import { toBufferBE } from '@aztec/foundation/bigint-buffer';
17
- import { Fr, type Point } from '@aztec/foundation/fields';
17
+ import { Fr } from '@aztec/foundation/fields';
18
18
  import {
19
19
  type AztecArray,
20
20
  type AztecKVStore,
@@ -66,6 +66,8 @@ export class KVPxeDatabase implements PxeDatabase {
66
66
  #notesByTxHashAndScope: Map<string, AztecMultiMap<string, string>>;
67
67
  #notesByIvpkMAndScope: Map<string, AztecMultiMap<string, string>>;
68
68
 
69
+ #taggingSecretIndexes: AztecMap<string, number>;
70
+
69
71
  constructor(private db: AztecKVStore) {
70
72
  this.#db = db;
71
73
 
@@ -111,6 +113,8 @@ export class KVPxeDatabase implements PxeDatabase {
111
113
  this.#notesByTxHashAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_tx_hash`));
112
114
  this.#notesByIvpkMAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_ivpk_m`));
113
115
  }
116
+
117
+ this.#taggingSecretIndexes = db.openMap('tagging_secret_indices');
114
118
  }
115
119
 
116
120
  public async getContract(
@@ -215,7 +219,7 @@ export class KVPxeDatabase implements PxeDatabase {
215
219
  const newLength = await this.#deferredNotes.push(...deferredNotes.map(note => note.toBuffer()));
216
220
  for (const [index, note] of deferredNotes.entries()) {
217
221
  const noteId = newLength - deferredNotes.length + index;
218
- await this.#deferredNotesByContract.set(note.contractAddress.toString(), noteId);
222
+ await this.#deferredNotesByContract.set(note.payload.contractAddress.toString(), noteId);
219
223
  }
220
224
  }
221
225
 
@@ -545,12 +549,12 @@ export class KVPxeDatabase implements PxeDatabase {
545
549
  return Promise.resolve(Array.from(this.#addresses).map(v => CompleteAddress.fromBuffer(v)));
546
550
  }
547
551
 
548
- getSynchedBlockNumberForPublicKey(publicKey: Point): number | undefined {
549
- return this.#syncedBlockPerPublicKey.get(publicKey.toString());
552
+ getSynchedBlockNumberForAccount(account: AztecAddress): number | undefined {
553
+ return this.#syncedBlockPerPublicKey.get(account.toString());
550
554
  }
551
555
 
552
- setSynchedBlockNumberForPublicKey(publicKey: Point, blockNumber: number): Promise<void> {
553
- return this.#syncedBlockPerPublicKey.set(publicKey.toString(), blockNumber);
556
+ setSynchedBlockNumberForAccount(account: AztecAddress, blockNumber: number): Promise<void> {
557
+ return this.#syncedBlockPerPublicKey.set(account.toString(), blockNumber);
554
558
  }
555
559
 
556
560
  async estimateSize(): Promise<number> {
@@ -572,4 +576,20 @@ export class KVPxeDatabase implements PxeDatabase {
572
576
 
573
577
  return incomingNotesSize + outgoingNotesSize + treeRootsSize + authWitsSize + addressesSize;
574
578
  }
579
+
580
+ async incrementTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<void> {
581
+ const indexes = await this.getTaggingSecretsIndexes(appTaggingSecrets);
582
+ await this.db.transaction(() => {
583
+ indexes.forEach(index => {
584
+ const nextIndex = index ? index + 1 : 1;
585
+ void this.#taggingSecretIndexes.set(appTaggingSecrets.toString(), nextIndex);
586
+ });
587
+ });
588
+ }
589
+
590
+ getTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<number[]> {
591
+ return this.db.transaction(() =>
592
+ appTaggingSecrets.map(secret => this.#taggingSecretIndexes.get(secret.toString()) ?? 0),
593
+ );
594
+ }
575
595
  }
@@ -35,6 +35,7 @@ export class OutgoingNoteDao {
35
35
  ) {}
36
36
 
37
37
  static fromPayloadAndNoteInfo(
38
+ note: Note,
38
39
  payload: L1NotePayload,
39
40
  noteInfo: NoteInfo,
40
41
  dataStartIndexForTx: number,
@@ -42,7 +43,7 @@ export class OutgoingNoteDao {
42
43
  ) {
43
44
  const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
44
45
  return new OutgoingNoteDao(
45
- payload.note,
46
+ note,
46
47
  payload.contractAddress,
47
48
  payload.storageSlot,
48
49
  payload.noteTypeId,
@@ -169,20 +169,24 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
169
169
 
170
170
  /**
171
171
  * Updates up to which block number we have processed notes for a given public key.
172
- * @param publicKey - The public key to set the synched block number for.
172
+ * @param account - The account to set the synched block number for.
173
173
  * @param blockNumber - The block number to set.
174
174
  */
175
- setSynchedBlockNumberForPublicKey(publicKey: PublicKey, blockNumber: number): Promise<void>;
175
+ setSynchedBlockNumberForAccount(account: AztecAddress, blockNumber: number): Promise<void>;
176
176
 
177
177
  /**
178
178
  * Get the synched block number for a given public key.
179
- * @param publicKey - The public key to get the synched block number for.
179
+ * @param account - The account to get the synched block number for.
180
180
  */
181
- getSynchedBlockNumberForPublicKey(publicKey: PublicKey): number | undefined;
181
+ getSynchedBlockNumberForAccount(account: AztecAddress): number | undefined;
182
182
 
183
183
  /**
184
184
  * Returns the estimated size in bytes of this db.
185
185
  * @returns The estimated size in bytes of this db.
186
186
  */
187
187
  estimateSize(): Promise<number>;
188
+
189
+ getTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<number[]>;
190
+
191
+ incrementTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<void>;
188
192
  }
@@ -1,6 +1,11 @@
1
1
  import { type AztecNode, L1NotePayload, type L2Block } from '@aztec/circuit-types';
2
2
  import { type NoteProcessorStats } from '@aztec/circuit-types/stats';
3
- import { type CompleteAddress, INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, type PublicKey } from '@aztec/circuits.js';
3
+ import {
4
+ type CompleteAddress,
5
+ INITIAL_L2_BLOCK_NUM,
6
+ MAX_NOTE_HASHES_PER_TX,
7
+ computeAddressSecret,
8
+ } from '@aztec/circuits.js';
4
9
  import { type Fr } from '@aztec/foundation/fields';
5
10
  import { type Logger, createDebugLogger } from '@aztec/foundation/log';
6
11
  import { Timer } from '@aztec/foundation/timer';
@@ -48,10 +53,6 @@ export class NoteProcessor {
48
53
 
49
54
  private constructor(
50
55
  public readonly account: CompleteAddress,
51
- /** The public counterpart to the secret key to be used in the decryption of incoming note logs. */
52
- private readonly ivpkM: PublicKey,
53
- /** The public counterpart to the secret key to be used in the decryption of outgoing note logs. */
54
- private readonly ovpkM: PublicKey,
55
56
  private keyStore: KeyStore,
56
57
  private db: PxeDatabase,
57
58
  private node: AztecNode,
@@ -60,7 +61,7 @@ export class NoteProcessor {
60
61
  private log: Logger,
61
62
  ) {}
62
63
 
63
- public static async create(
64
+ public static create(
64
65
  account: CompleteAddress,
65
66
  keyStore: KeyStore,
66
67
  db: PxeDatabase,
@@ -69,10 +70,7 @@ export class NoteProcessor {
69
70
  simulator = getAcirSimulator(db, node, keyStore),
70
71
  log = createDebugLogger('aztec:note_processor'),
71
72
  ) {
72
- const ivpkM = await keyStore.getMasterIncomingViewingPublicKey(account.address);
73
- const ovpkM = await keyStore.getMasterOutgoingViewingPublicKey(account.address);
74
-
75
- return new NoteProcessor(account, ivpkM, ovpkM, keyStore, db, node, startingBlock, simulator, log);
73
+ return new NoteProcessor(account, keyStore, db, node, startingBlock, simulator, log);
76
74
  }
77
75
 
78
76
  /**
@@ -95,7 +93,7 @@ export class NoteProcessor {
95
93
  }
96
94
 
97
95
  private getSyncedToBlock(): number {
98
- return this.db.getSynchedBlockNumberForPublicKey(this.ivpkM) ?? this.startingBlock - 1;
96
+ return this.db.getSynchedBlockNumberForAccount(this.account.address) ?? this.startingBlock - 1;
99
97
  }
100
98
 
101
99
  /**
@@ -114,13 +112,17 @@ export class NoteProcessor {
114
112
  const deferredIncomingNotes: DeferredNoteDao[] = [];
115
113
  const deferredOutgoingNotes: DeferredNoteDao[] = [];
116
114
 
117
- const ivskM = await this.keyStore.getMasterSecretKey(this.ivpkM);
118
- const ovskM = await this.keyStore.getMasterSecretKey(this.ovpkM);
115
+ const ivskM = await this.keyStore.getMasterSecretKey(this.account.publicKeys.masterIncomingViewingPublicKey);
116
+ const addressSecret = computeAddressSecret(this.account.getPreaddress(), ivskM);
117
+
118
+ const ovskM = await this.keyStore.getMasterSecretKey(this.account.publicKeys.masterOutgoingViewingPublicKey);
119
119
 
120
120
  // Iterate over both blocks and encrypted logs.
121
121
  for (const block of blocks) {
122
122
  this.stats.blocks++;
123
- const { txLogs } = block.body.noteEncryptedLogs;
123
+ const { txLogs: encryptedTxLogs } = block.body.noteEncryptedLogs;
124
+ const { txLogs: unencryptedTxLogs } = block.body.unencryptedLogs;
125
+
124
126
  const dataStartIndexForBlock =
125
127
  block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
126
128
  block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
@@ -131,65 +133,72 @@ export class NoteProcessor {
131
133
  const outgoingNotes: OutgoingNoteDao[] = [];
132
134
 
133
135
  // Iterate over all the encrypted logs and try decrypting them. If successful, store the note.
134
- for (let indexOfTxInABlock = 0; indexOfTxInABlock < txLogs.length; ++indexOfTxInABlock) {
136
+ for (let indexOfTxInABlock = 0; indexOfTxInABlock < encryptedTxLogs.length; ++indexOfTxInABlock) {
135
137
  this.stats.txs++;
136
138
  const dataStartIndexForTx = dataStartIndexForBlock + indexOfTxInABlock * MAX_NOTE_HASHES_PER_TX;
137
139
  const noteHashes = block.body.txEffects[indexOfTxInABlock].noteHashes;
138
140
  // Note: Each tx generates a `TxL2Logs` object and for this reason we can rely on its index corresponding
139
141
  // to the index of a tx in a block.
140
- const txFunctionLogs = txLogs[indexOfTxInABlock].functionLogs;
142
+ const encryptedTxFunctionLogs = encryptedTxLogs[indexOfTxInABlock].functionLogs;
143
+ const unencryptedTxFunctionLogs = unencryptedTxLogs[indexOfTxInABlock].functionLogs;
141
144
  const excludedIndices: Set<number> = new Set();
142
- for (const functionLogs of txFunctionLogs) {
143
- for (const log of functionLogs.logs) {
144
- this.stats.seen++;
145
- const incomingNotePayload = L1NotePayload.decryptAsIncoming(log, ivskM);
146
- const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(log, ovskM);
147
-
148
- if (incomingNotePayload || outgoingNotePayload) {
149
- if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
150
- throw new Error(
151
- `Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
152
- incomingNotePayload,
153
- )}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
154
- );
155
- }
156
-
157
- const payload = incomingNotePayload || outgoingNotePayload;
158
-
159
- const txEffect = block.body.txEffects[indexOfTxInABlock];
160
- const { incomingNote, outgoingNote, incomingDeferredNote, outgoingDeferredNote } = await produceNoteDaos(
161
- this.simulator,
162
- this.db,
163
- incomingNotePayload ? this.ivpkM : undefined,
164
- outgoingNotePayload ? this.ovpkM : undefined,
165
- payload!,
166
- txEffect.txHash,
167
- noteHashes,
168
- dataStartIndexForTx,
169
- excludedIndices,
170
- this.log,
171
- txEffect.unencryptedLogs,
172
- );
173
-
174
- if (incomingNote) {
175
- incomingNotes.push(incomingNote);
176
- this.stats.decryptedIncoming++;
177
- }
178
- if (outgoingNote) {
179
- outgoingNotes.push(outgoingNote);
180
- this.stats.decryptedOutgoing++;
181
- }
182
- if (incomingDeferredNote) {
183
- deferredIncomingNotes.push(incomingDeferredNote);
184
- this.stats.deferredIncoming++;
185
- }
186
- if (outgoingDeferredNote) {
187
- deferredOutgoingNotes.push(outgoingDeferredNote);
188
- this.stats.deferredOutgoing++;
189
- }
190
145
 
191
- if (incomingNote == undefined && outgoingNote == undefined && incomingDeferredNote == undefined) {
192
- this.stats.failed++;
146
+ // We iterate over both encrypted and unencrypted logs to decrypt the notes since partial notes are passed
147
+ // via the unencrypted logs stream.
148
+ for (const txFunctionLogs of [encryptedTxFunctionLogs, unencryptedTxFunctionLogs]) {
149
+ for (const functionLogs of txFunctionLogs) {
150
+ for (const unprocessedLog of functionLogs.logs) {
151
+ this.stats.seen++;
152
+ const incomingNotePayload = L1NotePayload.decryptAsIncoming(unprocessedLog.data, addressSecret);
153
+ const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(unprocessedLog.data, ovskM);
154
+
155
+ if (incomingNotePayload || outgoingNotePayload) {
156
+ if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
157
+ throw new Error(
158
+ `Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
159
+ incomingNotePayload,
160
+ )}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
161
+ );
162
+ }
163
+
164
+ const payload = incomingNotePayload || outgoingNotePayload;
165
+
166
+ const txEffect = block.body.txEffects[indexOfTxInABlock];
167
+ const { incomingNote, outgoingNote, incomingDeferredNote, outgoingDeferredNote } =
168
+ await produceNoteDaos(
169
+ this.simulator,
170
+ this.db,
171
+ incomingNotePayload ? this.account.publicKeys.masterIncomingViewingPublicKey : undefined,
172
+ outgoingNotePayload ? this.account.publicKeys.masterOutgoingViewingPublicKey : undefined,
173
+ payload!,
174
+ txEffect.txHash,
175
+ noteHashes,
176
+ dataStartIndexForTx,
177
+ excludedIndices,
178
+ this.log,
179
+ txEffect.unencryptedLogs,
180
+ );
181
+
182
+ if (incomingNote) {
183
+ incomingNotes.push(incomingNote);
184
+ this.stats.decryptedIncoming++;
185
+ }
186
+ if (outgoingNote) {
187
+ outgoingNotes.push(outgoingNote);
188
+ this.stats.decryptedOutgoing++;
189
+ }
190
+ if (incomingDeferredNote) {
191
+ deferredIncomingNotes.push(incomingDeferredNote);
192
+ this.stats.deferredIncoming++;
193
+ }
194
+ if (outgoingDeferredNote) {
195
+ deferredOutgoingNotes.push(outgoingDeferredNote);
196
+ this.stats.deferredOutgoing++;
197
+ }
198
+
199
+ if (incomingNote == undefined && outgoingNote == undefined && incomingDeferredNote == undefined) {
200
+ this.stats.failed++;
201
+ }
193
202
  }
194
203
  }
195
204
  }
@@ -207,7 +216,7 @@ export class NoteProcessor {
207
216
  await this.processDeferredNotes(deferredIncomingNotes, deferredOutgoingNotes);
208
217
 
209
218
  const syncedToBlock = blocks[blocks.length - 1].number;
210
- await this.db.setSynchedBlockNumberForPublicKey(this.ivpkM, syncedToBlock);
219
+ await this.db.setSynchedBlockNumberForAccount(this.account.address, syncedToBlock);
211
220
 
212
221
  this.log.debug(`Synched block ${syncedToBlock}`);
213
222
  }
@@ -241,7 +250,10 @@ export class NoteProcessor {
241
250
  const nullifiers: Fr[] = blocksAndNotes.flatMap(b =>
242
251
  b.block.body.txEffects.flatMap(txEffect => txEffect.nullifiers),
243
252
  );
244
- const removedNotes = await this.db.removeNullifiedNotes(nullifiers, this.ivpkM);
253
+ const removedNotes = await this.db.removeNullifiedNotes(
254
+ nullifiers,
255
+ this.account.publicKeys.masterIncomingViewingPublicKey,
256
+ );
245
257
  removedNotes.forEach(noteDao => {
246
258
  this.log.verbose(
247
259
  `Removed note for contract ${noteDao.contractAddress} at slot ${
@@ -265,15 +277,15 @@ export class NoteProcessor {
265
277
  await this.db.addDeferredNotes([...deferredIncomingNotes, ...deferredOutgoingNotes]);
266
278
  deferredIncomingNotes.forEach(noteDao => {
267
279
  this.log.verbose(
268
- `Deferred incoming note for contract ${noteDao.contractAddress} at slot ${
269
- noteDao.storageSlot
280
+ `Deferred incoming note for contract ${noteDao.payload.contractAddress} at slot ${
281
+ noteDao.payload.storageSlot
270
282
  } in tx ${noteDao.txHash.toString()}`,
271
283
  );
272
284
  });
273
285
  deferredOutgoingNotes.forEach(noteDao => {
274
286
  this.log.verbose(
275
- `Deferred outgoing note for contract ${noteDao.contractAddress} at slot ${
276
- noteDao.storageSlot
287
+ `Deferred outgoing note for contract ${noteDao.payload.contractAddress} at slot ${
288
+ noteDao.payload.storageSlot
277
289
  } in tx ${noteDao.txHash.toString()}`,
278
290
  );
279
291
  });
@@ -298,21 +310,10 @@ export class NoteProcessor {
298
310
  const outgoingNotes: OutgoingNoteDao[] = [];
299
311
 
300
312
  for (const deferredNote of deferredNoteDaos) {
301
- const {
302
- publicKey,
303
- note,
304
- contractAddress,
305
- storageSlot,
306
- noteTypeId,
307
- txHash,
308
- noteHashes,
309
- dataStartIndexForTx,
310
- unencryptedLogs,
311
- } = deferredNote;
312
- const payload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
313
+ const { publicKey, payload, txHash, noteHashes, dataStartIndexForTx, unencryptedLogs } = deferredNote;
313
314
 
314
- const isIncoming = publicKey.equals(this.ivpkM);
315
- const isOutgoing = publicKey.equals(this.ovpkM);
315
+ const isIncoming = publicKey.equals(this.account.publicKeys.masterIncomingViewingPublicKey);
316
+ const isOutgoing = publicKey.equals(this.account.publicKeys.masterOutgoingViewingPublicKey);
316
317
 
317
318
  if (!isIncoming && !isOutgoing) {
318
319
  // The note does not belong to this note processor
@@ -322,8 +323,8 @@ export class NoteProcessor {
322
323
  const { incomingNote, outgoingNote } = await produceNoteDaos(
323
324
  this.simulator,
324
325
  this.db,
325
- isIncoming ? this.ivpkM : undefined,
326
- isOutgoing ? this.ovpkM : undefined,
326
+ isIncoming ? this.account.publicKeys.masterIncomingViewingPublicKey : undefined,
327
+ isOutgoing ? this.account.publicKeys.masterOutgoingViewingPublicKey : undefined,
327
328
  payload,
328
329
  txHash,
329
330
  noteHashes,
@@ -0,0 +1,63 @@
1
+ import { type L1NotePayload, Note } from '@aztec/circuit-types';
2
+ import { ContractNotFoundError } from '@aztec/simulator';
3
+
4
+ import { type PxeDatabase } from '../../database/pxe_database.js';
5
+
6
+ /**
7
+ * Merges privately and publicly delivered note values.
8
+ * @param db - PXE database used to fetch contract instance and artifact.
9
+ * @param payload - Payload corresponding to the note.
10
+ * @returns Note payload with public fields added.
11
+ */
12
+ export async function getOrderedNoteItems(
13
+ db: PxeDatabase,
14
+ { contractAddress, noteTypeId, privateNoteValues, publicNoteValues }: L1NotePayload,
15
+ ): Promise<Note> {
16
+ if (publicNoteValues.length === 0) {
17
+ return new Note(privateNoteValues);
18
+ }
19
+
20
+ const instance = await db.getContractInstance(contractAddress);
21
+ if (!instance) {
22
+ throw new ContractNotFoundError(
23
+ `Could not find instance for ${contractAddress.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
24
+ );
25
+ }
26
+
27
+ const artifact = await db.getContractArtifact(instance.contractClassId);
28
+ if (!artifact) {
29
+ throw new Error(
30
+ `Could not find artifact for contract class ${instance.contractClassId.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
31
+ );
32
+ }
33
+
34
+ const noteFields = Object.values(artifact.notes).find(note => note.id.equals(noteTypeId))?.fields;
35
+
36
+ if (!noteFields) {
37
+ throw new Error(`Could not find note fields for note type ${noteTypeId.toString()}.`);
38
+ }
39
+
40
+ // We sort note fields by index so that we can iterate over them in order.
41
+ noteFields.sort((a, b) => a.index - b.index);
42
+
43
+ // Now we insert the public fields into the note based on its indices defined in the ABI.
44
+ const modifiedNoteItems = privateNoteValues;
45
+ let indexInPublicValues = 0;
46
+ for (let i = 0; i < noteFields.length; i++) {
47
+ const noteField = noteFields[i];
48
+ if (noteField.nullable) {
49
+ if (i == noteFields.length - 1) {
50
+ // We are processing the last field so we simply insert the rest of the public fields at the end
51
+ modifiedNoteItems.push(...publicNoteValues.slice(indexInPublicValues));
52
+ } else {
53
+ const noteFieldLength = noteFields[i + 1].index - noteField.index;
54
+ const publicValuesToInsert = publicNoteValues.slice(indexInPublicValues, indexInPublicValues + noteFieldLength);
55
+ indexInPublicValues += noteFieldLength;
56
+ // Now we insert the public fields at the note field index
57
+ modifiedNoteItems.splice(noteField.index, 0, ...publicValuesToInsert);
58
+ }
59
+ }
60
+ }
61
+
62
+ return new Note(modifiedNoteItems);
63
+ }
@@ -1,5 +1,7 @@
1
- import { type L1NotePayload, type TxHash } from '@aztec/circuit-types';
1
+ import { type Note, type TxHash } from '@aztec/circuit-types';
2
+ import { type AztecAddress } from '@aztec/circuits.js';
2
3
  import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
4
+ import { type NoteSelector } from '@aztec/foundation/abi';
3
5
  import { Fr } from '@aztec/foundation/fields';
4
6
  import { type AcirSimulator } from '@aztec/simulator';
5
7
 
@@ -18,7 +20,10 @@ export interface NoteInfo {
18
20
  * @remarks This method assists in identifying spent notes in the note hash tree.
19
21
  * @param siloedNoteHashes - Note hashes in the tx. One of them should correspond to the note we are looking for
20
22
  * @param txHash - Hash of a tx the note was emitted in.
21
- * @param l1NotePayload - The note payload.
23
+ * @param contractAddress - Address of the contract the note was emitted in.
24
+ * @param storageSlot - Storage slot of the note.
25
+ * @param noteTypeId - Type of the note.
26
+ * @param note - Note items.
22
27
  * @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
23
28
  * l1NotePayload. We need to find a different index for each replicate.
24
29
  * @param computeNullifier - A flag indicating whether to compute the nullifier or just return 0.
@@ -29,7 +34,10 @@ export async function bruteForceNoteInfo(
29
34
  simulator: AcirSimulator,
30
35
  siloedNoteHashes: Fr[],
31
36
  txHash: TxHash,
32
- { contractAddress, storageSlot, noteTypeId, note }: L1NotePayload,
37
+ contractAddress: AztecAddress,
38
+ storageSlot: Fr,
39
+ noteTypeId: NoteSelector,
40
+ note: Note,
33
41
  excludedIndices: Set<number>,
34
42
  computeNullifier: boolean,
35
43
  ): Promise<NoteInfo> {
@@ -46,8 +46,6 @@ export async function produceNoteDaos(
46
46
  incomingDeferredNote: DeferredNoteDao | undefined;
47
47
  outgoingDeferredNote: DeferredNoteDao | undefined;
48
48
  }> {
49
- // WARNING: This code is full of tech debt and will be refactored once we have final design of partial notes
50
- // delivery.
51
49
  if (!ivpkM && !ovpkM) {
52
50
  throw new Error('Both ivpkM and ovpkM are undefined. Cannot create note.');
53
51
  }
@@ -78,11 +76,11 @@ export async function produceNoteDaos(
78
76
  // Incoming note is defined meaning that this PXE has both the incoming and outgoing keys. We can skip computing
79
77
  // note hash and note index since we already have them in the incoming note.
80
78
  outgoingNote = new OutgoingNoteDao(
81
- payload.note,
82
- payload.contractAddress,
83
- payload.storageSlot,
84
- payload.noteTypeId,
85
- txHash,
79
+ incomingNote.note,
80
+ incomingNote.contractAddress,
81
+ incomingNote.storageSlot,
82
+ incomingNote.noteTypeId,
83
+ incomingNote.txHash,
86
84
  incomingNote.nonce,
87
85
  incomingNote.noteHash,
88
86
  incomingNote.index,