@aztec/pxe 0.87.6 → 1.0.0-nightly.20250604

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 (42) hide show
  1. package/dest/config/package_info.js +1 -1
  2. package/dest/contract_function_simulator/execution_data_provider.d.ts +20 -16
  3. package/dest/contract_function_simulator/execution_data_provider.d.ts.map +1 -1
  4. package/dest/contract_function_simulator/note_validation_request.d.ts +21 -0
  5. package/dest/contract_function_simulator/note_validation_request.d.ts.map +1 -0
  6. package/dest/contract_function_simulator/note_validation_request.js +42 -0
  7. package/dest/contract_function_simulator/oracle/oracle.d.ts +3 -2
  8. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/oracle/oracle.js +21 -12
  10. package/dest/contract_function_simulator/oracle/typed_oracle.d.ts +4 -3
  11. package/dest/contract_function_simulator/oracle/typed_oracle.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/oracle/typed_oracle.js +7 -4
  13. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +4 -3
  14. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +8 -5
  16. package/dest/contract_function_simulator/pxe_oracle_interface.d.ts +6 -4
  17. package/dest/contract_function_simulator/pxe_oracle_interface.d.ts.map +1 -1
  18. package/dest/contract_function_simulator/pxe_oracle_interface.js +57 -21
  19. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
  20. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.js +30 -30
  21. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  22. package/dest/private_kernel/private_kernel_execution_prover.js +9 -7
  23. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  24. package/dest/pxe_service/pxe_service.js +10 -3
  25. package/dest/storage/capsule_data_provider/capsule_data_provider.d.ts +4 -2
  26. package/dest/storage/capsule_data_provider/capsule_data_provider.d.ts.map +1 -1
  27. package/dest/storage/capsule_data_provider/capsule_data_provider.js +46 -7
  28. package/dest/storage/note_data_provider/note_data_provider.d.ts.map +1 -1
  29. package/dest/storage/note_data_provider/note_data_provider.js +14 -14
  30. package/package.json +16 -16
  31. package/src/config/package_info.ts +1 -1
  32. package/src/contract_function_simulator/execution_data_provider.ts +22 -26
  33. package/src/contract_function_simulator/note_validation_request.ts +52 -0
  34. package/src/contract_function_simulator/oracle/oracle.ts +24 -25
  35. package/src/contract_function_simulator/oracle/typed_oracle.ts +14 -14
  36. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +10 -24
  37. package/src/contract_function_simulator/pxe_oracle_interface.ts +98 -22
  38. package/src/private_kernel/hints/build_private_kernel_reset_private_inputs.ts +35 -34
  39. package/src/private_kernel/private_kernel_execution_prover.ts +11 -10
  40. package/src/pxe_service/pxe_service.ts +10 -3
  41. package/src/storage/capsule_data_provider/capsule_data_provider.ts +56 -7
  42. package/src/storage/note_data_provider/note_data_provider.ts +22 -22
@@ -6,7 +6,6 @@ import {
6
6
  MAX_NULLIFIER_READ_REQUESTS_PER_TX,
7
7
  MAX_PRIVATE_LOGS_PER_TX,
8
8
  NULLIFIER_TREE_HEIGHT,
9
- VK_TREE_HEIGHT,
10
9
  } from '@aztec/constants';
11
10
  import { makeTuple } from '@aztec/foundation/array';
12
11
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -16,6 +15,7 @@ import { MembershipWitness } from '@aztec/foundation/trees';
16
15
  import { privateKernelResetDimensionsConfig } from '@aztec/noir-protocol-circuits-types/client';
17
16
  import {
18
17
  KeyValidationHint,
18
+ PaddedSideEffects,
19
19
  type PrivateCircuitPublicInputs,
20
20
  type PrivateKernelCircuitPublicInputs,
21
21
  PrivateKernelData,
@@ -42,6 +42,7 @@ import {
42
42
  privateKernelResetDimensionNames,
43
43
  } from '@aztec/stdlib/kernel';
44
44
  import { type PrivateCallExecutionResult, collectNested } from '@aztec/stdlib/tx';
45
+ import { VkData } from '@aztec/stdlib/vks';
45
46
 
46
47
  import type { PrivateKernelOracle } from '../private_kernel_oracle.js';
47
48
 
@@ -74,22 +75,17 @@ function getNullifierMembershipWitnessResolver(oracle: PrivateKernelOracle) {
74
75
 
75
76
  async function getMasterSecretKeysAndAppKeyGenerators(
76
77
  keyValidationRequests: Tuple<ScopedKeyValidationRequestAndGenerator, typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX>,
78
+ numRequestsToVerify: number,
77
79
  oracle: PrivateKernelOracle,
78
80
  ) {
79
- const keysHints = [];
80
- for (let i = 0; i < keyValidationRequests.length; ++i) {
81
- const request = keyValidationRequests[i].request;
82
- if (request.isEmpty()) {
83
- break;
84
- }
85
- const secretKeys = await oracle.getMasterSecretKey(request.request.pkM);
86
- keysHints.push(new KeyValidationHint(secretKeys, i));
87
- }
88
- return padArrayEnd(
89
- keysHints,
90
- KeyValidationHint.nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX),
91
- MAX_KEY_VALIDATION_REQUESTS_PER_TX,
81
+ const numRequests = countAccumulatedItems(keyValidationRequests);
82
+ const keysHints = await Promise.all(
83
+ keyValidationRequests.slice(0, Math.min(numRequests, numRequestsToVerify)).map(async ({ request }) => {
84
+ const secretKeys = await oracle.getMasterSecretKey(request.request.pkM);
85
+ return new KeyValidationHint(secretKeys);
86
+ }),
92
87
  );
88
+ return padArrayEnd(keysHints, KeyValidationHint.empty(), MAX_KEY_VALIDATION_REQUESTS_PER_TX);
93
89
  }
94
90
 
95
91
  export class PrivateKernelResetPrivateInputsBuilder {
@@ -166,26 +162,30 @@ export class PrivateKernelResetPrivateInputsBuilder {
166
162
  const previousVkMembershipWitness = await oracle.getVkMembershipWitness(
167
163
  this.previousKernelOutput.verificationKey.keyAsFields,
168
164
  );
169
- const previousKernelData = new PrivateKernelData(
170
- this.previousKernelOutput.publicInputs,
165
+ const vkData = new VkData(
171
166
  this.previousKernelOutput.verificationKey,
172
167
  Number(previousVkMembershipWitness.leafIndex),
173
- assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
168
+ previousVkMembershipWitness.siblingPath,
174
169
  );
170
+ const previousKernelData = new PrivateKernelData(this.previousKernelOutput.publicInputs, vkData);
175
171
 
176
172
  this.reduceReadRequestStates(
177
173
  this.noteHashResetStates,
178
- dimensions.NOTE_HASH_PENDING_AMOUNT,
179
- dimensions.NOTE_HASH_SETTLED_AMOUNT,
174
+ dimensions.NOTE_HASH_PENDING_READ,
175
+ dimensions.NOTE_HASH_SETTLED_READ,
180
176
  );
181
177
  this.reduceReadRequestStates(
182
178
  this.nullifierResetStates,
183
- dimensions.NULLIFIER_PENDING_AMOUNT,
184
- dimensions.NULLIFIER_SETTLED_AMOUNT,
179
+ dimensions.NULLIFIER_PENDING_READ,
180
+ dimensions.NULLIFIER_SETTLED_READ,
185
181
  );
186
182
 
183
+ // TODO: Enable padding when we have a better idea what are the final amounts we should pad to.
184
+ const paddedSideEffects = PaddedSideEffects.empty();
185
+
187
186
  return new PrivateKernelResetCircuitPrivateInputs(
188
187
  previousKernelData,
188
+ paddedSideEffects,
189
189
  new PrivateKernelResetHints(
190
190
  await buildNoteHashReadRequestHintsFromResetStates(
191
191
  oracle,
@@ -201,6 +201,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
201
201
  ),
202
202
  await getMasterSecretKeysAndAppKeyGenerators(
203
203
  this.previousKernel.validationRequests.scopedKeyValidationRequestsAndGenerators,
204
+ dimensions.KEY_VALIDATION,
204
205
  oracle,
205
206
  ),
206
207
  this.transientDataIndexHints,
@@ -266,19 +267,19 @@ export class PrivateKernelResetPrivateInputsBuilder {
266
267
 
267
268
  if (!this.nextIteration) {
268
269
  this.noteHashResetStates = resetStates;
269
- this.requestedDimensions.NOTE_HASH_PENDING_AMOUNT = numPendingReads;
270
- this.requestedDimensions.NOTE_HASH_SETTLED_AMOUNT = numSettledReads;
270
+ this.requestedDimensions.NOTE_HASH_PENDING_READ = numPendingReads;
271
+ this.requestedDimensions.NOTE_HASH_SETTLED_READ = numSettledReads;
271
272
  } else {
272
273
  // Pick only one dimension to reset if next iteration is not empty.
273
274
  if (numPendingReads > numSettledReads) {
274
- this.requestedDimensions.NOTE_HASH_PENDING_AMOUNT = numPendingReads;
275
+ this.requestedDimensions.NOTE_HASH_PENDING_READ = numPendingReads;
275
276
  this.noteHashResetStates.states = assertLength(
276
277
  resetStates.states.map(state => (state === ReadRequestState.PENDING ? state : ReadRequestState.NADA)),
277
278
  MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
278
279
  );
279
280
  this.noteHashResetStates.pendingReadHints = resetStates.pendingReadHints;
280
281
  } else {
281
- this.requestedDimensions.NOTE_HASH_SETTLED_AMOUNT = numSettledReads;
282
+ this.requestedDimensions.NOTE_HASH_SETTLED_READ = numSettledReads;
282
283
  this.noteHashResetStates.states = assertLength(
283
284
  resetStates.states.map(state => (state === ReadRequestState.SETTLED ? state : ReadRequestState.NADA)),
284
285
  MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
@@ -318,19 +319,19 @@ export class PrivateKernelResetPrivateInputsBuilder {
318
319
 
319
320
  if (!this.nextIteration) {
320
321
  this.nullifierResetStates = resetStates;
321
- this.requestedDimensions.NULLIFIER_PENDING_AMOUNT = numPendingReads;
322
- this.requestedDimensions.NULLIFIER_SETTLED_AMOUNT = numSettledReads;
322
+ this.requestedDimensions.NULLIFIER_PENDING_READ = numPendingReads;
323
+ this.requestedDimensions.NULLIFIER_SETTLED_READ = numSettledReads;
323
324
  } else {
324
325
  // Pick only one dimension to reset if next iteration is not empty.
325
326
  if (numPendingReads > numSettledReads) {
326
- this.requestedDimensions.NULLIFIER_PENDING_AMOUNT = numPendingReads;
327
+ this.requestedDimensions.NULLIFIER_PENDING_READ = numPendingReads;
327
328
  this.nullifierResetStates.states = assertLength(
328
329
  resetStates.states.map(state => (state === ReadRequestState.PENDING ? state : ReadRequestState.NADA)),
329
330
  MAX_NULLIFIER_READ_REQUESTS_PER_TX,
330
331
  );
331
332
  this.nullifierResetStates.pendingReadHints = resetStates.pendingReadHints;
332
333
  } else {
333
- this.requestedDimensions.NULLIFIER_SETTLED_AMOUNT = numSettledReads;
334
+ this.requestedDimensions.NULLIFIER_SETTLED_READ = numSettledReads;
334
335
  this.nullifierResetStates.states = assertLength(
335
336
  resetStates.states.map(state => (state === ReadRequestState.SETTLED ? state : ReadRequestState.NADA)),
336
337
  MAX_NULLIFIER_READ_REQUESTS_PER_TX,
@@ -353,7 +354,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
353
354
  return false;
354
355
  }
355
356
 
356
- this.requestedDimensions.NULLIFIER_KEYS = numCurr;
357
+ this.requestedDimensions.KEY_VALIDATION = numCurr;
357
358
 
358
359
  return true;
359
360
  }
@@ -430,7 +431,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
430
431
 
431
432
  this.numTransientData = numTransientData;
432
433
  this.transientDataIndexHints = transientDataIndexHints;
433
- this.requestedDimensions.TRANSIENT_DATA_AMOUNT = numTransientData;
434
+ this.requestedDimensions.TRANSIENT_DATA_SQUASHING = numTransientData;
434
435
 
435
436
  return numTransientData > 0;
436
437
  }
@@ -442,7 +443,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
442
443
 
443
444
  const numNoteHashes = this.previousKernel.end.noteHashes.filter(n => !n.contractAddress.isZero()).length;
444
445
  const numToSilo = Math.max(0, numNoteHashes - this.numTransientData);
445
- this.requestedDimensions.NOTE_HASH_SILOING_AMOUNT = numToSilo;
446
+ this.requestedDimensions.NOTE_HASH_SILOING = numToSilo;
446
447
 
447
448
  return numToSilo > 0;
448
449
  }
@@ -458,7 +459,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
458
459
  // The reset circuit checks that capped_size must be greater than or equal to all non-empty nullifiers.
459
460
  // Which includes the first nullifier, even though its contract address is always zero and doesn't need siloing.
460
461
  const cappedSize = numToSilo ? numToSilo + 1 : 0;
461
- this.requestedDimensions.NULLIFIER_SILOING_AMOUNT = cappedSize;
462
+ this.requestedDimensions.NULLIFIER_SILOING = cappedSize;
462
463
 
463
464
  return numToSilo > 0;
464
465
  }
@@ -478,7 +479,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
478
479
  const numSquashedLogs = privateLogs.filter(l => squashedNoteHashCounters.includes(l.inner.noteHashCounter)).length;
479
480
 
480
481
  const numToSilo = numLogs - numSquashedLogs;
481
- this.requestedDimensions.PRIVATE_LOG_SILOING_AMOUNT = numToSilo;
482
+ this.requestedDimensions.PRIVATE_LOG_SILOING = numToSilo;
482
483
 
483
484
  return numToSilo > 0;
484
485
  }
@@ -1,8 +1,6 @@
1
- import { VK_TREE_HEIGHT } from '@aztec/constants';
2
1
  import { vkAsFieldsMegaHonk } from '@aztec/foundation/crypto';
3
2
  import { Fr } from '@aztec/foundation/fields';
4
3
  import { createLogger } from '@aztec/foundation/log';
5
- import { assertLength } from '@aztec/foundation/serialize';
6
4
  import { pushTestData } from '@aztec/foundation/testing';
7
5
  import { Timer } from '@aztec/foundation/timer';
8
6
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
@@ -12,6 +10,7 @@ import { computeContractAddressFromInstance } from '@aztec/stdlib/contract';
12
10
  import { hashVK } from '@aztec/stdlib/hash';
13
11
  import type { PrivateKernelProver } from '@aztec/stdlib/interfaces/client';
14
12
  import {
13
+ PaddedSideEffectAmounts,
15
14
  PrivateCallData,
16
15
  type PrivateExecutionStep,
17
16
  PrivateKernelCircuitPublicInputs,
@@ -33,7 +32,7 @@ import {
33
32
  collectNoteHashNullifierCounterMap,
34
33
  getFinalMinRevertibleSideEffectCounter,
35
34
  } from '@aztec/stdlib/tx';
36
- import { VerificationKeyAsFields, VerificationKeyData } from '@aztec/stdlib/vks';
35
+ import { VerificationKeyAsFields, VerificationKeyData, VkData } from '@aztec/stdlib/vks';
37
36
 
38
37
  import { PrivateKernelResetPrivateInputsBuilder } from './hints/build_private_kernel_reset_private_inputs.js';
39
38
  import type { PrivateKernelOracle } from './private_kernel_oracle.js';
@@ -195,12 +194,12 @@ export class PrivateKernelExecutionProver {
195
194
  const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(
196
195
  output.verificationKey.keyAsFields,
197
196
  );
198
- const previousKernelData = new PrivateKernelData(
199
- output.publicInputs,
197
+ const vkData = new VkData(
200
198
  output.verificationKey,
201
199
  Number(previousVkMembershipWitness.leafIndex),
202
- assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
200
+ previousVkMembershipWitness.siblingPath,
203
201
  );
202
+ const previousKernelData = new PrivateKernelData(output.publicInputs, vkData);
204
203
  const proofInput = new PrivateKernelInnerCircuitPrivateInputs(previousKernelData, privateCallData);
205
204
 
206
205
  pushTestData('private-kernel-inputs-inner', proofInput);
@@ -261,18 +260,20 @@ export class PrivateKernelExecutionProver {
261
260
  }
262
261
  // Private tail.
263
262
  const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey.keyAsFields);
264
- const previousKernelData = new PrivateKernelData(
265
- output.publicInputs,
263
+ const vkData = new VkData(
266
264
  output.verificationKey,
267
265
  Number(previousVkMembershipWitness.leafIndex),
268
- assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
266
+ previousVkMembershipWitness.siblingPath,
269
267
  );
268
+ const previousKernelData = new PrivateKernelData(output.publicInputs, vkData);
270
269
 
271
270
  this.log.debug(
272
271
  `Calling private kernel tail with hwm ${previousKernelData.publicInputs.minRevertibleSideEffectCounter}`,
273
272
  );
274
273
 
275
- const privateInputs = new PrivateKernelTailCircuitPrivateInputs(previousKernelData);
274
+ // TODO: Enable padding when we have a better what are the final amounts we should pad to.
275
+ const paddedSideEffectAmounts = PaddedSideEffectAmounts.empty();
276
+ const privateInputs = new PrivateKernelTailCircuitPrivateInputs(previousKernelData, paddedSideEffectAmounts);
276
277
 
277
278
  pushTestData('private-kernel-inputs-ordering', privateInputs);
278
279
 
@@ -49,7 +49,7 @@ import type {
49
49
  } from '@aztec/stdlib/interfaces/client';
50
50
  import type { PrivateKernelExecutionProofOutput, PrivateKernelTailCircuitPublicInputs } from '@aztec/stdlib/kernel';
51
51
  import type { LogFilter } from '@aztec/stdlib/logs';
52
- import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
52
+ import { computeL2ToL1MembershipWitness, getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
53
53
  import { type NotesFilter, UniqueNote } from '@aztec/stdlib/note';
54
54
  import { MerkleTreeId } from '@aztec/stdlib/trees';
55
55
  import {
@@ -196,8 +196,15 @@ export class PXEService implements PXE {
196
196
  return this.node.isL1ToL2MessageSynced(l1ToL2Message);
197
197
  }
198
198
 
199
- public getL2ToL1MembershipWitness(blockNumber: number, l2Tol1Message: Fr): Promise<[bigint, SiblingPath<number>]> {
200
- return this.node.getL2ToL1MessageMembershipWitness(blockNumber, l2Tol1Message);
199
+ public async getL2ToL1MembershipWitness(
200
+ blockNumber: number,
201
+ l2Tol1Message: Fr,
202
+ ): Promise<[bigint, SiblingPath<number>]> {
203
+ const result = await computeL2ToL1MembershipWitness(this.node, blockNumber, l2Tol1Message);
204
+ if (!result) {
205
+ throw new Error(`L2 to L1 message not found in block ${blockNumber}`);
206
+ }
207
+ return [result.l2MessageIndex, result.siblingPath];
201
208
  }
202
209
 
203
210
  public getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
@@ -75,26 +75,71 @@ export class CapsuleDataProvider implements DataProvider {
75
75
  * All operations are performed in a single transaction.
76
76
  * @param contractAddress - The contract address that owns the capsule array
77
77
  * @param baseSlot - The slot where the array length is stored
78
- * @param capsules - Array of capsule data to append
78
+ * @param content - Array of capsule data to append
79
79
  */
80
- appendToCapsuleArray(contractAddress: AztecAddress, baseSlot: Fr, capsules: Fr[][]): Promise<void> {
80
+ appendToCapsuleArray(contractAddress: AztecAddress, baseSlot: Fr, content: Fr[][]): Promise<void> {
81
81
  return this.#store.transactionAsync(async () => {
82
82
  // Load current length, defaulting to 0 if not found
83
83
  const lengthData = await this.loadCapsule(contractAddress, baseSlot);
84
- const currentLength = lengthData ? lengthData[0].toBigInt() : 0n;
84
+ const currentLength = lengthData ? lengthData[0].toNumber() : 0;
85
85
 
86
86
  // Store each capsule at consecutive slots after baseSlot + 1 + currentLength
87
- for (let i = 0; i < capsules.length; i++) {
88
- const nextSlot = baseSlot.add(new Fr(1)).add(new Fr(currentLength + BigInt(i)));
89
- await this.storeCapsule(contractAddress, nextSlot, capsules[i]);
87
+ for (let i = 0; i < content.length; i++) {
88
+ const nextSlot = arraySlot(baseSlot, currentLength + i);
89
+ await this.storeCapsule(contractAddress, nextSlot, content[i]);
90
90
  }
91
91
 
92
92
  // Update length to include all new capsules
93
- const newLength = currentLength + BigInt(capsules.length);
93
+ const newLength = currentLength + content.length;
94
94
  await this.storeCapsule(contractAddress, baseSlot, [new Fr(newLength)]);
95
95
  });
96
96
  }
97
97
 
98
+ readCapsuleArray(contractAddress: AztecAddress, baseSlot: Fr): Promise<Fr[][]> {
99
+ return this.#store.transactionAsync(async () => {
100
+ // Load length, defaulting to 0 if not found
101
+ const maybeLength = await this.loadCapsule(contractAddress, baseSlot);
102
+ const length = maybeLength ? maybeLength[0].toBigInt() : 0n;
103
+
104
+ const values: Fr[][] = [];
105
+
106
+ // Read each capsule at consecutive slots after baseSlot
107
+ for (let i = 0; i < length; i++) {
108
+ const currentValue = await this.loadCapsule(contractAddress, arraySlot(baseSlot, i));
109
+ if (currentValue == undefined) {
110
+ throw new Error(
111
+ `Expected non-empty value at capsule array in base slot ${baseSlot} at index ${i} for contract ${contractAddress}`,
112
+ );
113
+ }
114
+
115
+ values.push(currentValue);
116
+ }
117
+
118
+ return values;
119
+ });
120
+ }
121
+
122
+ resetCapsuleArray(contractAddress: AztecAddress, baseSlot: Fr, content: Fr[][]) {
123
+ return this.#store.transactionAsync(async () => {
124
+ // Load current length, defaulting to 0 if not found
125
+ const maybeLength = await this.loadCapsule(contractAddress, baseSlot);
126
+ const originalLength = maybeLength ? maybeLength[0].toNumber() : 0;
127
+
128
+ // Set the new length
129
+ await this.storeCapsule(contractAddress, baseSlot, [new Fr(content.length)]);
130
+
131
+ // Store the new content, possibly overwriting existing values
132
+ for (let i = 0; i < content.length; i++) {
133
+ await this.storeCapsule(contractAddress, arraySlot(baseSlot, i), content[i]);
134
+ }
135
+
136
+ // Clear any stragglers
137
+ for (let i = content.length; i < originalLength; i++) {
138
+ await this.deleteCapsule(contractAddress, arraySlot(baseSlot, i));
139
+ }
140
+ });
141
+ }
142
+
98
143
  public async getSize() {
99
144
  return (await toArray(this.#capsules.valuesAsync())).reduce(
100
145
  (sum, value) => sum + value.length * Fr.SIZE_IN_BYTES,
@@ -106,3 +151,7 @@ export class CapsuleDataProvider implements DataProvider {
106
151
  function dbSlotToKey(contractAddress: AztecAddress, slot: Fr): string {
107
152
  return `${contractAddress.toString()}:${slot.toString()}`;
108
153
  }
154
+
155
+ function arraySlot(baseSlot: Fr, index: number) {
156
+ return baseSlot.add(new Fr(1)).add(new Fr(index));
157
+ }
@@ -80,12 +80,12 @@ export class NoteDataProvider implements DataProvider {
80
80
  return true;
81
81
  }
82
82
 
83
- async addNotes(notes: NoteDao[], scope: AztecAddress = AztecAddress.ZERO): Promise<void> {
84
- if (!(await this.#scopes.hasAsync(scope.toString()))) {
85
- await this.addScope(scope);
86
- }
87
-
83
+ addNotes(notes: NoteDao[], scope: AztecAddress = AztecAddress.ZERO): Promise<void> {
88
84
  return this.#store.transactionAsync(async () => {
85
+ if (!(await this.#scopes.hasAsync(scope.toString()))) {
86
+ await this.addScope(scope);
87
+ }
88
+
89
89
  for (const dao of notes) {
90
90
  // store notes by their index in the notes hash tree
91
91
  // this provides the uniqueness we need to store individual notes
@@ -127,24 +127,24 @@ export class NoteDataProvider implements DataProvider {
127
127
  }
128
128
 
129
129
  public async unnullifyNotesAfter(blockNumber: number, synchedBlockNumber?: number): Promise<void> {
130
- const nullifiersToUndo: string[] = [];
131
- const currentBlockNumber = blockNumber + 1;
132
- const maxBlockNumber = synchedBlockNumber ?? currentBlockNumber;
133
- for (let i = currentBlockNumber; i <= maxBlockNumber; i++) {
134
- nullifiersToUndo.push(...(await toArray(this.#nullifiersByBlockNumber.getValuesAsync(i))));
135
- }
136
- const notesIndexesToReinsert = await Promise.all(
137
- nullifiersToUndo.map(nullifier => this.#nullifiedNotesByNullifier.getAsync(nullifier)),
138
- );
139
- const notNullNoteIndexes = notesIndexesToReinsert.filter(noteIndex => noteIndex != undefined);
140
- const nullifiedNoteBuffers = await Promise.all(
141
- notNullNoteIndexes.map(noteIndex => this.#nullifiedNotes.getAsync(noteIndex!)),
142
- );
143
- const noteDaos = nullifiedNoteBuffers
144
- .filter(buffer => buffer != undefined)
145
- .map(buffer => NoteDao.fromBuffer(buffer!));
146
-
147
130
  await this.#store.transactionAsync(async () => {
131
+ const nullifiersToUndo: string[] = [];
132
+ const currentBlockNumber = blockNumber + 1;
133
+ const maxBlockNumber = synchedBlockNumber ?? currentBlockNumber;
134
+ for (let i = currentBlockNumber; i <= maxBlockNumber; i++) {
135
+ nullifiersToUndo.push(...(await toArray(this.#nullifiersByBlockNumber.getValuesAsync(i))));
136
+ }
137
+ const notesIndexesToReinsert = await Promise.all(
138
+ nullifiersToUndo.map(nullifier => this.#nullifiedNotesByNullifier.getAsync(nullifier)),
139
+ );
140
+ const notNullNoteIndexes = notesIndexesToReinsert.filter(noteIndex => noteIndex != undefined);
141
+ const nullifiedNoteBuffers = await Promise.all(
142
+ notNullNoteIndexes.map(noteIndex => this.#nullifiedNotes.getAsync(noteIndex!)),
143
+ );
144
+ const noteDaos = nullifiedNoteBuffers
145
+ .filter(buffer => buffer != undefined)
146
+ .map(buffer => NoteDao.fromBuffer(buffer!));
147
+
148
148
  for (const dao of noteDaos) {
149
149
  const noteIndex = toBufferBE(dao.index, 32).toString('hex');
150
150
  await this.#notes.set(noteIndex, dao.toBuffer());