@aztec/pxe 0.47.1 → 0.48.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 (66) hide show
  1. package/dest/config/index.d.ts +17 -0
  2. package/dest/config/index.d.ts.map +1 -1
  3. package/dest/config/index.js +67 -8
  4. package/dest/database/incoming_note_dao.d.ts +4 -4
  5. package/dest/database/incoming_note_dao.d.ts.map +1 -1
  6. package/dest/database/incoming_note_dao.js +7 -7
  7. package/dest/database/kv_pxe_database.d.ts +3 -3
  8. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  9. package/dest/database/kv_pxe_database.js +64 -31
  10. package/dest/database/outgoing_note_dao.d.ts +6 -6
  11. package/dest/database/outgoing_note_dao.d.ts.map +1 -1
  12. package/dest/database/outgoing_note_dao.js +8 -8
  13. package/dest/database/pxe_database.d.ts +6 -2
  14. package/dest/database/pxe_database.d.ts.map +1 -1
  15. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  16. package/dest/database/pxe_database_test_suite.js +43 -4
  17. package/dest/kernel_prover/{private_inputs_builders → hints}/build_private_kernel_reset_hints.d.ts +1 -1
  18. package/dest/kernel_prover/hints/build_private_kernel_reset_hints.d.ts.map +1 -0
  19. package/dest/kernel_prover/hints/build_private_kernel_reset_hints.js +77 -0
  20. package/dest/kernel_prover/hints/index.d.ts +3 -0
  21. package/dest/kernel_prover/hints/index.d.ts.map +1 -0
  22. package/dest/kernel_prover/hints/index.js +3 -0
  23. package/dest/kernel_prover/hints/needs_reset.d.ts +5 -0
  24. package/dest/kernel_prover/hints/needs_reset.d.ts.map +1 -0
  25. package/dest/kernel_prover/hints/needs_reset.js +35 -0
  26. package/dest/kernel_prover/kernel_prover.d.ts +0 -2
  27. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  28. package/dest/kernel_prover/kernel_prover.js +14 -38
  29. package/dest/note_processor/note_processor.js +2 -2
  30. package/dest/note_processor/produce_note_dao.js +15 -15
  31. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
  32. package/dest/pxe_http/pxe_http_server.js +3 -1
  33. package/dest/pxe_service/create_pxe_service.js +2 -2
  34. package/dest/pxe_service/pxe_service.d.ts +4 -4
  35. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  36. package/dest/pxe_service/pxe_service.js +23 -30
  37. package/dest/simulator_oracle/index.d.ts +2 -2
  38. package/dest/simulator_oracle/index.d.ts.map +1 -1
  39. package/dest/simulator_oracle/index.js +5 -4
  40. package/dest/synchronizer/synchronizer.d.ts +1 -1
  41. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  42. package/dest/synchronizer/synchronizer.js +8 -10
  43. package/package.json +14 -14
  44. package/src/config/index.ts +84 -14
  45. package/src/database/incoming_note_dao.ts +5 -5
  46. package/src/database/kv_pxe_database.ts +86 -31
  47. package/src/database/outgoing_note_dao.ts +6 -6
  48. package/src/database/pxe_database.ts +6 -2
  49. package/src/database/pxe_database_test_suite.ts +70 -3
  50. package/src/kernel_prover/{private_inputs_builders → hints}/build_private_kernel_reset_hints.ts +2 -0
  51. package/src/kernel_prover/hints/index.ts +2 -0
  52. package/src/kernel_prover/hints/needs_reset.ts +51 -0
  53. package/src/kernel_prover/kernel_prover.ts +20 -48
  54. package/src/note_processor/note_processor.ts +1 -1
  55. package/src/note_processor/produce_note_dao.ts +14 -14
  56. package/src/pxe_http/pxe_http_server.ts +2 -0
  57. package/src/pxe_service/create_pxe_service.ts +2 -2
  58. package/src/pxe_service/pxe_service.ts +41 -51
  59. package/src/simulator_oracle/index.ts +4 -3
  60. package/src/synchronizer/synchronizer.ts +19 -19
  61. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts.map +0 -1
  62. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.js +0 -77
  63. package/dest/kernel_prover/private_inputs_builders/index.d.ts +0 -2
  64. package/dest/kernel_prover/private_inputs_builders/index.d.ts.map +0 -1
  65. package/dest/kernel_prover/private_inputs_builders/index.js +0 -2
  66. package/src/kernel_prover/private_inputs_builders/index.ts +0 -1
@@ -1,4 +1,11 @@
1
1
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants';
2
+ import {
3
+ type ConfigMappingsType,
4
+ booleanConfigHelper,
5
+ getConfigFromMappings,
6
+ numberConfigHelper,
7
+ } from '@aztec/foundation/config';
8
+ import { type Network } from '@aztec/types/network';
2
9
 
3
10
  import { readFileSync } from 'fs';
4
11
  import { dirname, resolve } from 'path';
@@ -33,26 +40,89 @@ export interface PXEConfig {
33
40
 
34
41
  export type PXEServiceConfig = PXEConfig & KernelProverConfig & BBProverConfig;
35
42
 
43
+ export type CliPXEOptions = {
44
+ /** External Aztec network to connect to. e.g. devnet */
45
+ network?: Network;
46
+ /** API Key required by the external network's node */
47
+ apiKey?: string;
48
+ /** Custom Aztec Node URL to connect to */
49
+ nodeUrl?: string;
50
+ };
51
+
52
+ export const pxeConfigMappings: ConfigMappingsType<PXEServiceConfig> = {
53
+ l2BlockPollingIntervalMS: {
54
+ env: 'PXE_BLOCK_POLLING_INTERVAL_MS',
55
+ description: 'The interval to wait between polling for new blocks.',
56
+ ...numberConfigHelper(1_000),
57
+ },
58
+ l2StartingBlock: {
59
+ env: 'PXE_L2_STARTING_BLOCK',
60
+ ...numberConfigHelper(INITIAL_L2_BLOCK_NUM),
61
+ description: 'L2 block to start scanning from for new accounts',
62
+ },
63
+ dataDirectory: {
64
+ env: 'PXE_DATA_DIRECTORY',
65
+ description: 'Where to store PXE data. If not set, will store in memory',
66
+ },
67
+ bbBinaryPath: {
68
+ env: 'BB_BINARY_PATH',
69
+ description: 'Path to the BB binary',
70
+ },
71
+ bbWorkingDirectory: {
72
+ env: 'BB_WORKING_DIRECTORY',
73
+ description: 'Working directory for the BB binary',
74
+ },
75
+ proverEnabled: {
76
+ env: 'PXE_PROVER_ENABLED',
77
+ description: 'Enable real proofs',
78
+ ...booleanConfigHelper(),
79
+ },
80
+ };
81
+
36
82
  /**
37
83
  * Creates an instance of PXEServiceConfig out of environment variables using sensible defaults for integration testing if not set.
38
84
  */
39
85
  export function getPXEServiceConfig(): PXEServiceConfig {
40
- const {
41
- PXE_BLOCK_POLLING_INTERVAL_MS,
42
- PXE_L2_STARTING_BLOCK,
43
- PXE_DATA_DIRECTORY,
44
- BB_BINARY_PATH,
45
- BB_WORKING_DIRECTORY,
46
- PXE_PROVER_ENABLED,
47
- } = process.env;
86
+ return getConfigFromMappings<PXEServiceConfig>(pxeConfigMappings);
87
+ }
88
+
89
+ export const pxeCliConfigMappings: ConfigMappingsType<CliPXEOptions> = {
90
+ network: {
91
+ env: 'NETWORK',
92
+ parseEnv: (val: string) => val as Network,
93
+ description: 'External Aztec network to connect to. e.g. devnet',
94
+ },
95
+ apiKey: {
96
+ env: 'API_KEY',
97
+ description: "API Key required by the external network's node",
98
+ },
99
+ nodeUrl: {
100
+ env: 'AZTEC_NODE_URL',
101
+ description: 'Custom Aztec Node URL to connect to',
102
+ },
103
+ };
48
104
 
105
+ export const allPxeConfigMappings: ConfigMappingsType<CliPXEOptions & PXEServiceConfig> = {
106
+ ...pxeConfigMappings,
107
+ ...pxeCliConfigMappings,
108
+ proverEnabled: {
109
+ env: 'PXE_PROVER_ENABLED',
110
+ parseEnv: (val: string) => ['1', 'true', 'TRUE'].includes(val) || !!process.env.NETWORK,
111
+ description: 'Enable real proofs',
112
+ isBoolean: true,
113
+ },
114
+ };
115
+
116
+ /**
117
+ * Creates an instance of CliPxeOptions out of environment variables
118
+ */
119
+ export function getCliPXEOptions(): CliPXEOptions & PXEServiceConfig {
120
+ const pxeConfig = getPXEServiceConfig();
121
+ const cliOptions = getConfigFromMappings<CliPXEOptions>(pxeCliConfigMappings);
49
122
  return {
50
- l2BlockPollingIntervalMS: PXE_BLOCK_POLLING_INTERVAL_MS ? +PXE_BLOCK_POLLING_INTERVAL_MS : 1000,
51
- l2StartingBlock: PXE_L2_STARTING_BLOCK ? +PXE_L2_STARTING_BLOCK : INITIAL_L2_BLOCK_NUM,
52
- dataDirectory: PXE_DATA_DIRECTORY,
53
- bbBinaryPath: BB_BINARY_PATH,
54
- bbWorkingDirectory: BB_WORKING_DIRECTORY,
55
- proverEnabled: ['1', 'true'].includes(PXE_PROVER_ENABLED!),
123
+ ...pxeConfig,
124
+ ...cliOptions,
125
+ proverEnabled: pxeConfig.proverEnabled || !!cliOptions.network,
56
126
  };
57
127
  }
58
128
 
@@ -23,10 +23,10 @@ export class IncomingNoteDao implements NoteData {
23
23
  /** The nonce of the note. */
24
24
  public nonce: Fr,
25
25
  /**
26
- * Inner note hash of the note. This is customizable by the app circuit.
26
+ * A hash of the note. This is customizable by the app circuit.
27
27
  * We can use this value to compute siloedNoteHash and uniqueSiloedNoteHash.
28
28
  */
29
- public innerNoteHash: Fr,
29
+ public noteHash: Fr,
30
30
  /**
31
31
  * The nullifier of the note (siloed by contract address).
32
32
  * Note: Might be set as 0 if the note was added to PXE as nullified.
@@ -46,7 +46,7 @@ export class IncomingNoteDao implements NoteData {
46
46
  this.noteTypeId,
47
47
  this.txHash.buffer,
48
48
  this.nonce,
49
- this.innerNoteHash,
49
+ this.noteHash,
50
50
  this.siloedNullifier,
51
51
  this.index,
52
52
  this.ivpkM,
@@ -61,7 +61,7 @@ export class IncomingNoteDao implements NoteData {
61
61
  const noteTypeId = reader.readObject(NoteSelector);
62
62
  const txHash = reader.readObject(TxHash);
63
63
  const nonce = Fr.fromBuffer(reader);
64
- const innerNoteHash = Fr.fromBuffer(reader);
64
+ const noteHash = Fr.fromBuffer(reader);
65
65
  const siloedNullifier = Fr.fromBuffer(reader);
66
66
  const index = toBigIntBE(reader.readBytes(32));
67
67
  const publicKey = Point.fromBuffer(reader);
@@ -73,7 +73,7 @@ export class IncomingNoteDao implements NoteData {
73
73
  noteTypeId,
74
74
  txHash,
75
75
  nonce,
76
- innerNoteHash,
76
+ noteHash,
77
77
  siloedNullifier,
78
78
  index,
79
79
  publicKey,
@@ -14,6 +14,7 @@ import {
14
14
  type AztecKVStore,
15
15
  type AztecMap,
16
16
  type AztecMultiMap,
17
+ type AztecSet,
17
18
  type AztecSingleton,
18
19
  } from '@aztec/kv-store';
19
20
  import { contractArtifactFromBuffer, contractArtifactToBuffer } from '@aztec/types/abi';
@@ -36,10 +37,7 @@ export class KVPxeDatabase implements PxeDatabase {
36
37
  #notes: AztecMap<string, Buffer>;
37
38
  #nullifiedNotes: AztecMap<string, Buffer>;
38
39
  #nullifierToNoteId: AztecMap<string, string>;
39
- #notesByContract: AztecMultiMap<string, string>;
40
- #notesByStorageSlot: AztecMultiMap<string, string>;
41
- #notesByTxHash: AztecMultiMap<string, string>;
42
- #notesByIvpkM: AztecMultiMap<string, string>;
40
+
43
41
  #nullifiedNotesByContract: AztecMultiMap<string, string>;
44
42
  #nullifiedNotesByStorageSlot: AztecMultiMap<string, string>;
45
43
  #nullifiedNotesByTxHash: AztecMultiMap<string, string>;
@@ -57,6 +55,12 @@ export class KVPxeDatabase implements PxeDatabase {
57
55
  #outgoingNotesByTxHash: AztecMultiMap<string, string>;
58
56
  #outgoingNotesByOvpkM: AztecMultiMap<string, string>;
59
57
 
58
+ #scopes: AztecSet<string>;
59
+ #notesByContractAndScope: Map<string, AztecMultiMap<string, string>>;
60
+ #notesByStorageSlotAndScope: Map<string, AztecMultiMap<string, string>>;
61
+ #notesByTxHashAndScope: Map<string, AztecMultiMap<string, string>>;
62
+ #notesByIvpkMAndScope: Map<string, AztecMultiMap<string, string>>;
63
+
60
64
  constructor(private db: AztecKVStore) {
61
65
  this.#db = db;
62
66
 
@@ -76,11 +80,6 @@ export class KVPxeDatabase implements PxeDatabase {
76
80
  this.#nullifiedNotes = db.openMap('nullified_notes');
77
81
  this.#nullifierToNoteId = db.openMap('nullifier_to_note');
78
82
 
79
- this.#notesByContract = db.openMultiMap('notes_by_contract');
80
- this.#notesByStorageSlot = db.openMultiMap('notes_by_storage_slot');
81
- this.#notesByTxHash = db.openMultiMap('notes_by_tx_hash');
82
- this.#notesByIvpkM = db.openMultiMap('notes_by_ivpk_m');
83
-
84
83
  this.#nullifiedNotesByContract = db.openMultiMap('nullified_notes_by_contract');
85
84
  this.#nullifiedNotesByStorageSlot = db.openMultiMap('nullified_notes_by_storage_slot');
86
85
  this.#nullifiedNotesByTxHash = db.openMultiMap('nullified_notes_by_tx_hash');
@@ -94,6 +93,19 @@ export class KVPxeDatabase implements PxeDatabase {
94
93
  this.#outgoingNotesByStorageSlot = db.openMultiMap('outgoing_notes_by_storage_slot');
95
94
  this.#outgoingNotesByTxHash = db.openMultiMap('outgoing_notes_by_tx_hash');
96
95
  this.#outgoingNotesByOvpkM = db.openMultiMap('outgoing_notes_by_ovpk_m');
96
+
97
+ this.#scopes = db.openSet('scopes');
98
+ this.#notesByContractAndScope = new Map<string, AztecMultiMap<string, string>>();
99
+ this.#notesByStorageSlotAndScope = new Map<string, AztecMultiMap<string, string>>();
100
+ this.#notesByTxHashAndScope = new Map<string, AztecMultiMap<string, string>>();
101
+ this.#notesByIvpkMAndScope = new Map<string, AztecMultiMap<string, string>>();
102
+
103
+ for (const scope of this.#scopes.entries()) {
104
+ this.#notesByContractAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_contract`));
105
+ this.#notesByStorageSlotAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_storage_slot`));
106
+ this.#notesByTxHashAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_tx_hash`));
107
+ this.#notesByIvpkMAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_ivpk_m`));
108
+ }
97
109
  }
98
110
 
99
111
  public async getContract(
@@ -154,11 +166,19 @@ export class KVPxeDatabase implements PxeDatabase {
154
166
  return val?.map(b => Fr.fromBuffer(b));
155
167
  }
156
168
 
157
- async addNote(note: IncomingNoteDao): Promise<void> {
158
- await this.addNotes([note], []);
169
+ async addNote(note: IncomingNoteDao, scope?: AztecAddress): Promise<void> {
170
+ await this.addNotes([note], [], scope);
159
171
  }
160
172
 
161
- addNotes(incomingNotes: IncomingNoteDao[], outgoingNotes: OutgoingNoteDao[]): Promise<void> {
173
+ async addNotes(
174
+ incomingNotes: IncomingNoteDao[],
175
+ outgoingNotes: OutgoingNoteDao[],
176
+ scope: AztecAddress = AztecAddress.ZERO,
177
+ ): Promise<void> {
178
+ if (!this.#scopes.has(scope.toString())) {
179
+ await this.#addScope(scope);
180
+ }
181
+
162
182
  return this.db.transaction(() => {
163
183
  for (const dao of incomingNotes) {
164
184
  // store notes by their index in the notes hash tree
@@ -168,10 +188,11 @@ export class KVPxeDatabase implements PxeDatabase {
168
188
  const noteIndex = toBufferBE(dao.index, 32).toString('hex');
169
189
  void this.#notes.set(noteIndex, dao.toBuffer());
170
190
  void this.#nullifierToNoteId.set(dao.siloedNullifier.toString(), noteIndex);
171
- void this.#notesByContract.set(dao.contractAddress.toString(), noteIndex);
172
- void this.#notesByStorageSlot.set(dao.storageSlot.toString(), noteIndex);
173
- void this.#notesByTxHash.set(dao.txHash.toString(), noteIndex);
174
- void this.#notesByIvpkM.set(dao.ivpkM.toString(), noteIndex);
191
+
192
+ void this.#notesByContractAndScope.get(scope.toString())!.set(dao.contractAddress.toString(), noteIndex);
193
+ void this.#notesByStorageSlotAndScope.get(scope.toString())!.set(dao.storageSlot.toString(), noteIndex);
194
+ void this.#notesByTxHashAndScope.get(scope.toString())!.set(dao.txHash.toString(), noteIndex);
195
+ void this.#notesByIvpkMAndScope.get(scope.toString())!.set(dao.ivpkM.toString(), noteIndex);
175
196
  }
176
197
 
177
198
  for (const dao of outgoingNotes) {
@@ -244,16 +265,31 @@ export class KVPxeDatabase implements PxeDatabase {
244
265
 
245
266
  const candidateNoteSources = [];
246
267
 
268
+ filter.scopes ??= [...this.#scopes.entries()].map(addressString => AztecAddress.fromString(addressString));
269
+
270
+ const activeNoteIdsPerScope: IterableIterator<string>[] = [];
271
+
272
+ for (const scope of new Set(filter.scopes)) {
273
+ const formattedScopeString = scope.toString();
274
+ if (!this.#scopes.has(formattedScopeString)) {
275
+ throw new Error('Trying to get incoming notes of an scope that is not in the PXE database');
276
+ }
277
+
278
+ activeNoteIdsPerScope.push(
279
+ publicKey
280
+ ? this.#notesByIvpkMAndScope.get(formattedScopeString)!.getValues(publicKey.toString())
281
+ : filter.txHash
282
+ ? this.#notesByTxHashAndScope.get(formattedScopeString)!.getValues(filter.txHash.toString())
283
+ : filter.contractAddress
284
+ ? this.#notesByContractAndScope.get(formattedScopeString)!.getValues(filter.contractAddress.toString())
285
+ : filter.storageSlot
286
+ ? this.#notesByStorageSlotAndScope.get(formattedScopeString)!.getValues(filter.storageSlot.toString())
287
+ : this.#notesByIvpkMAndScope.get(formattedScopeString)!.values(),
288
+ );
289
+ }
290
+
247
291
  candidateNoteSources.push({
248
- ids: publicKey
249
- ? this.#notesByIvpkM.getValues(publicKey.toString())
250
- : filter.txHash
251
- ? this.#notesByTxHash.getValues(filter.txHash.toString())
252
- : filter.contractAddress
253
- ? this.#notesByContract.getValues(filter.contractAddress.toString())
254
- : filter.storageSlot
255
- ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString())
256
- : this.#notes.keys(),
292
+ ids: new Set(activeNoteIdsPerScope.flatMap(iterableIterator => [...iterableIterator])),
257
293
  notes: this.#notes,
258
294
  });
259
295
 
@@ -358,7 +394,7 @@ export class KVPxeDatabase implements PxeDatabase {
358
394
  return Promise.resolve(notes);
359
395
  }
360
396
 
361
- removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<IncomingNoteDao[]> {
397
+ removeNullifiedNotes(nullifiers: Fr[], accountIvpkM: PublicKey): Promise<IncomingNoteDao[]> {
362
398
  if (nullifiers.length === 0) {
363
399
  return Promise.resolve([]);
364
400
  }
@@ -380,7 +416,7 @@ export class KVPxeDatabase implements PxeDatabase {
380
416
  }
381
417
 
382
418
  const note = IncomingNoteDao.fromBuffer(noteBuffer);
383
- if (!note.ivpkM.equals(account)) {
419
+ if (!note.ivpkM.equals(accountIvpkM)) {
384
420
  // tried to nullify someone else's note
385
421
  continue;
386
422
  }
@@ -388,10 +424,13 @@ export class KVPxeDatabase implements PxeDatabase {
388
424
  nullifiedNotes.push(note);
389
425
 
390
426
  void this.#notes.delete(noteIndex);
391
- void this.#notesByIvpkM.deleteValue(account.toString(), noteIndex);
392
- void this.#notesByTxHash.deleteValue(note.txHash.toString(), noteIndex);
393
- void this.#notesByContract.deleteValue(note.contractAddress.toString(), noteIndex);
394
- void this.#notesByStorageSlot.deleteValue(note.storageSlot.toString(), noteIndex);
427
+
428
+ for (const scope in this.#scopes.entries()) {
429
+ void this.#notesByIvpkMAndScope.get(scope)!.deleteValue(accountIvpkM.toString(), noteIndex);
430
+ void this.#notesByTxHashAndScope.get(scope)!.deleteValue(note.txHash.toString(), noteIndex);
431
+ void this.#notesByContractAndScope.get(scope)!.deleteValue(note.contractAddress.toString(), noteIndex);
432
+ void this.#notesByStorageSlotAndScope.get(scope)!.deleteValue(note.storageSlot.toString(), noteIndex);
433
+ }
395
434
 
396
435
  void this.#nullifiedNotes.set(noteIndex, note.toBuffer());
397
436
  void this.#nullifiedNotesByContract.set(note.contractAddress.toString(), noteIndex);
@@ -440,6 +479,22 @@ export class KVPxeDatabase implements PxeDatabase {
440
479
  return Header.fromBuffer(headerBuffer);
441
480
  }
442
481
 
482
+ async #addScope(scope: AztecAddress): Promise<boolean> {
483
+ const scopeString = scope.toString();
484
+
485
+ if (this.#scopes.has(scopeString)) {
486
+ return false;
487
+ }
488
+
489
+ await this.#scopes.add(scopeString);
490
+ this.#notesByContractAndScope.set(scopeString, this.#db.openMultiMap(`${scopeString}:notes_by_contract`));
491
+ this.#notesByStorageSlotAndScope.set(scopeString, this.#db.openMultiMap(`${scopeString}:notes_by_storage_slot`));
492
+ this.#notesByTxHashAndScope.set(scopeString, this.#db.openMultiMap(`${scopeString}:notes_by_tx_hash`));
493
+ this.#notesByIvpkMAndScope.set(scopeString, this.#db.openMultiMap(`${scopeString}:notes_by_ivpk_m`));
494
+
495
+ return true;
496
+ }
497
+
443
498
  addCompleteAddress(completeAddress: CompleteAddress): Promise<boolean> {
444
499
  return this.#db.transaction(() => {
445
500
  const addressString = completeAddress.address.toString();
@@ -22,10 +22,10 @@ export class OutgoingNoteDao {
22
22
  /** The nonce of the note. */
23
23
  public nonce: Fr,
24
24
  /**
25
- * Inner note hash of the note. This is customizable by the app circuit.
26
- * We can use this value to compute siloedNoteHash and uniqueSiloedNoteHash.
25
+ * A hash of the note. This is customizable by the app circuit.
26
+ * We can use this value to compute unique note hash and then siloed note hash.
27
27
  */
28
- public innerNoteHash: Fr,
28
+ public noteHash: Fr,
29
29
  /** The location of the relevant note in the note hash tree. */
30
30
  public index: bigint,
31
31
  /** The public key with which the note was encrypted. */
@@ -40,7 +40,7 @@ export class OutgoingNoteDao {
40
40
  this.noteTypeId,
41
41
  this.txHash.buffer,
42
42
  this.nonce,
43
- this.innerNoteHash,
43
+ this.noteHash,
44
44
  this.index,
45
45
  this.ovpkM,
46
46
  ]);
@@ -54,7 +54,7 @@ export class OutgoingNoteDao {
54
54
  const noteTypeId = reader.readObject(NoteSelector);
55
55
  const txHash = new TxHash(reader.readBytes(TxHash.SIZE));
56
56
  const nonce = Fr.fromBuffer(reader);
57
- const innerNoteHash = Fr.fromBuffer(reader);
57
+ const noteHash = Fr.fromBuffer(reader);
58
58
  const index = toBigIntBE(reader.readBytes(32));
59
59
  const publicKey = Point.fromBuffer(reader);
60
60
 
@@ -65,7 +65,7 @@ export class OutgoingNoteDao {
65
65
  noteTypeId,
66
66
  txHash,
67
67
  nonce,
68
- innerNoteHash,
68
+ noteHash,
69
69
  index,
70
70
  publicKey,
71
71
  );
@@ -62,8 +62,10 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
62
62
  /**
63
63
  * Adds a note to DB.
64
64
  * @param note - The note to add.
65
+ * @param scope - The scope to add the note under. Currently optional.
66
+ * @remark - Will create a database for the scope if it does not already exist.
65
67
  */
66
- addNote(note: IncomingNoteDao): Promise<void>;
68
+ addNote(note: IncomingNoteDao, scope?: AztecAddress): Promise<void>;
67
69
 
68
70
  /**
69
71
  * Adds a nullified note to DB.
@@ -78,8 +80,10 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
78
80
  *
79
81
  * @param incomingNotes - An array of notes which were decrypted as incoming.
80
82
  * @param outgoingNotes - An array of notes which were decrypted as outgoing.
83
+ * @param scope - The scope to add the notes under. Currently optional.
84
+ * @remark - Will create a database for the scope if it does not already exist.
81
85
  */
82
- addNotes(incomingNotes: IncomingNoteDao[], outgoingNotes: OutgoingNoteDao[]): Promise<void>;
86
+ addNotes(incomingNotes: IncomingNoteDao[], outgoingNotes: OutgoingNoteDao[], scope?: AztecAddress): Promise<void>;
83
87
 
84
88
  /**
85
89
  * Add notes to the database that are intended for us, but we don't yet have the contract.
@@ -130,14 +130,19 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
130
130
 
131
131
  it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
132
132
  await database.addNotes(notes, []);
133
- await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
133
+ const returnedNotes = await database.getIncomingNotes(getFilter());
134
+
135
+ expect(returnedNotes.sort()).toEqual(getExpected().sort());
134
136
  });
135
137
 
136
138
  it.each(filteringTests)('stores notes one by one and retrieves notes', async (getFilter, getExpected) => {
137
139
  for (const note of notes) {
138
140
  await database.addNote(note);
139
141
  }
140
- await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
142
+
143
+ const returnedNotes = await database.getIncomingNotes(getFilter());
144
+
145
+ expect(returnedNotes.sort()).toEqual(getExpected().sort());
141
146
  });
142
147
 
143
148
  it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => {
@@ -196,6 +201,68 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
196
201
  // inserted combining active and nullified results.
197
202
  expect(result.sort()).toEqual([...notes].sort());
198
203
  });
204
+
205
+ it('stores notes one by one and retrieves notes with siloed account', async () => {
206
+ for (const note of notes.slice(0, 5)) {
207
+ await database.addNote(note, owners[0].address);
208
+ }
209
+
210
+ for (const note of notes.slice(5)) {
211
+ await database.addNote(note, owners[1].address);
212
+ }
213
+
214
+ const owner0IncomingNotes = await database.getIncomingNotes({
215
+ scopes: [owners[0].address],
216
+ });
217
+
218
+ expect(owner0IncomingNotes.sort()).toEqual(notes.slice(0, 5).sort());
219
+
220
+ const owner1IncomingNotes = await database.getIncomingNotes({
221
+ scopes: [owners[1].address],
222
+ });
223
+
224
+ expect(owner1IncomingNotes.sort()).toEqual(notes.slice(5).sort());
225
+
226
+ const bothOwnerIncomingNotes = await database.getIncomingNotes({
227
+ scopes: [owners[0].address, owners[1].address],
228
+ });
229
+
230
+ expect(bothOwnerIncomingNotes.sort()).toEqual(notes.sort());
231
+ });
232
+
233
+ it('a nullified note removes notes from all accounts in the pxe', async () => {
234
+ await database.addNote(notes[0], owners[0].address);
235
+ await database.addNote(notes[0], owners[1].address);
236
+
237
+ await expect(
238
+ database.getIncomingNotes({
239
+ scopes: [owners[0].address],
240
+ }),
241
+ ).resolves.toEqual([notes[0]]);
242
+ await expect(
243
+ database.getIncomingNotes({
244
+ scopes: [owners[1].address],
245
+ }),
246
+ ).resolves.toEqual([notes[0]]);
247
+
248
+ await expect(
249
+ database.removeNullifiedNotes(
250
+ [notes[0].siloedNullifier],
251
+ owners[0].publicKeys.masterIncomingViewingPublicKey,
252
+ ),
253
+ ).resolves.toEqual([notes[0]]);
254
+
255
+ await expect(
256
+ database.getIncomingNotes({
257
+ scopes: [owners[0].address],
258
+ }),
259
+ ).resolves.toEqual([]);
260
+ await expect(
261
+ database.getIncomingNotes({
262
+ scopes: [owners[1].address],
263
+ }),
264
+ ).resolves.toEqual([]);
265
+ });
199
266
  });
200
267
 
201
268
  describe('outgoing notes', () => {
@@ -264,7 +331,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
264
331
 
265
332
  describe('block header', () => {
266
333
  it('stores and retrieves the block header', async () => {
267
- const header = makeHeader(randomInt(1000), INITIAL_L2_BLOCK_NUM);
334
+ const header = makeHeader(randomInt(1000), INITIAL_L2_BLOCK_NUM, 0 /** slot number */);
268
335
 
269
336
  await database.setHeader(header);
270
337
  expect(database.getHeader()).toEqual(header);
@@ -91,6 +91,7 @@ export async function buildPrivateKernelResetInputs(
91
91
  previousKernelData: PrivateKernelData,
92
92
  noteHashLeafIndexMap: Map<bigint, bigint>,
93
93
  noteHashNullifierCounterMap: Map<number, number>,
94
+ validationRequestsSplitCounter: number,
94
95
  oracle: ProvingDataOracle,
95
96
  ) {
96
97
  const publicInputs = previousKernelData.publicInputs;
@@ -181,6 +182,7 @@ export async function buildPrivateKernelResetInputs(
181
182
  noteHashReadRequestHints,
182
183
  nullifierReadRequestHints,
183
184
  keysHints,
185
+ validationRequestsSplitCounter,
184
186
  ).trimToSizes(
185
187
  hintSizes.NOTE_HASH_PENDING_AMOUNT,
186
188
  hintSizes.NOTE_HASH_SETTLED_AMOUNT,
@@ -0,0 +1,2 @@
1
+ export * from './build_private_kernel_reset_hints.js';
2
+ export * from './needs_reset.js';
@@ -0,0 +1,51 @@
1
+ import {
2
+ MAX_KEY_VALIDATION_REQUESTS_PER_TX,
3
+ MAX_NOTE_ENCRYPTED_LOGS_PER_TX,
4
+ MAX_NOTE_HASHES_PER_TX,
5
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
6
+ MAX_NULLIFIERS_PER_TX,
7
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
8
+ type PrivateKernelCircuitPublicInputs,
9
+ getNonEmptyItems,
10
+ } from '@aztec/circuits.js';
11
+ import { type ExecutionResult } from '@aztec/simulator';
12
+
13
+ export function needsReset(publicInputs: PrivateKernelCircuitPublicInputs, executionStack: ExecutionResult[]) {
14
+ const nextIteration = executionStack[executionStack.length - 1];
15
+ return (
16
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.noteHashes).length +
17
+ getNonEmptyItems(publicInputs.end.noteHashes).length >
18
+ MAX_NOTE_HASHES_PER_TX ||
19
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.nullifiers).length +
20
+ getNonEmptyItems(publicInputs.end.nullifiers).length >
21
+ MAX_NULLIFIERS_PER_TX ||
22
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.noteEncryptedLogsHashes).length +
23
+ getNonEmptyItems(publicInputs.end.noteEncryptedLogsHashes).length >
24
+ MAX_NOTE_ENCRYPTED_LOGS_PER_TX ||
25
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.noteHashReadRequests).length +
26
+ getNonEmptyItems(publicInputs.validationRequests.noteHashReadRequests).length >
27
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX ||
28
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.nullifierReadRequests).length +
29
+ getNonEmptyItems(publicInputs.validationRequests.nullifierReadRequests).length >
30
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX ||
31
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.keyValidationRequestsAndGenerators).length +
32
+ getNonEmptyItems(publicInputs.validationRequests.scopedKeyValidationRequestsAndGenerators).length >
33
+ MAX_KEY_VALIDATION_REQUESTS_PER_TX
34
+ );
35
+ }
36
+
37
+ function hasTransientNullifier(publicInputs: PrivateKernelCircuitPublicInputs) {
38
+ const noteHashSet = new Set();
39
+ publicInputs.end.noteHashes.forEach(n => noteHashSet.add(n.noteHash.value.toBigInt()));
40
+ noteHashSet.delete(0n);
41
+ return publicInputs.end.nullifiers.some(n => noteHashSet.has(n.nullifiedNoteHash.toBigInt()));
42
+ }
43
+
44
+ export function somethingToReset(publicInputs: PrivateKernelCircuitPublicInputs) {
45
+ return (
46
+ getNonEmptyItems(publicInputs.validationRequests.noteHashReadRequests).length > 0 ||
47
+ getNonEmptyItems(publicInputs.validationRequests.nullifierReadRequests).length > 0 ||
48
+ getNonEmptyItems(publicInputs.validationRequests.scopedKeyValidationRequestsAndGenerators).length > 0 ||
49
+ hasTransientNullifier(publicInputs)
50
+ );
51
+ }