@aztec/simulator 0.65.1 → 0.66.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 (61) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +0 -3
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +1 -17
  4. package/dest/acvm/oracle/typed_oracle.d.ts +0 -5
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +1 -10
  7. package/dest/avm/avm_memory_types.js +4 -4
  8. package/dest/avm/avm_simulator.d.ts.map +1 -1
  9. package/dest/avm/avm_simulator.js +5 -4
  10. package/dest/avm/avm_tree.d.ts +31 -14
  11. package/dest/avm/avm_tree.d.ts.map +1 -1
  12. package/dest/avm/avm_tree.js +34 -40
  13. package/dest/avm/journal/journal.d.ts.map +1 -1
  14. package/dest/avm/journal/journal.js +16 -10
  15. package/dest/avm/opcodes/environment_getters.d.ts +10 -11
  16. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  17. package/dest/avm/opcodes/environment_getters.js +12 -15
  18. package/dest/client/client_execution_context.d.ts +3 -30
  19. package/dest/client/client_execution_context.d.ts.map +1 -1
  20. package/dest/client/client_execution_context.js +5 -47
  21. package/dest/client/private_execution.d.ts.map +1 -1
  22. package/dest/client/private_execution.js +2 -4
  23. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  24. package/dest/public/enqueued_call_side_effect_trace.js +15 -15
  25. package/dest/public/fixtures/index.d.ts +1 -6
  26. package/dest/public/fixtures/index.d.ts.map +1 -1
  27. package/dest/public/fixtures/index.js +24 -11
  28. package/dest/public/public_db_sources.d.ts.map +1 -1
  29. package/dest/public/public_db_sources.js +27 -13
  30. package/dest/public/public_processor.d.ts.map +1 -1
  31. package/dest/public/public_processor.js +8 -5
  32. package/dest/public/public_processor_metrics.d.ts +1 -1
  33. package/dest/public/public_processor_metrics.d.ts.map +1 -1
  34. package/dest/public/public_tx_context.d.ts +2 -6
  35. package/dest/public/public_tx_context.d.ts.map +1 -1
  36. package/dest/public/public_tx_context.js +23 -29
  37. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  38. package/dest/public/public_tx_simulator.js +18 -5
  39. package/dest/public/side_effect_trace.js +8 -8
  40. package/dest/public/transitional_adapters.d.ts +2 -6
  41. package/dest/public/transitional_adapters.d.ts.map +1 -1
  42. package/dest/public/transitional_adapters.js +4 -67
  43. package/package.json +9 -9
  44. package/src/acvm/oracle/oracle.ts +0 -30
  45. package/src/acvm/oracle/typed_oracle.ts +0 -17
  46. package/src/avm/avm_memory_types.ts +4 -4
  47. package/src/avm/avm_simulator.ts +4 -3
  48. package/src/avm/avm_tree.ts +67 -53
  49. package/src/avm/journal/journal.ts +21 -9
  50. package/src/avm/opcodes/environment_getters.ts +1 -4
  51. package/src/client/client_execution_context.ts +5 -59
  52. package/src/client/private_execution.ts +0 -4
  53. package/src/public/enqueued_call_side_effect_trace.ts +14 -16
  54. package/src/public/fixtures/index.ts +30 -10
  55. package/src/public/public_db_sources.ts +29 -16
  56. package/src/public/public_processor.ts +6 -8
  57. package/src/public/public_processor_metrics.ts +1 -1
  58. package/src/public/public_tx_context.ts +37 -44
  59. package/src/public/public_tx_simulator.ts +19 -13
  60. package/src/public/side_effect_trace.ts +7 -7
  61. package/src/public/transitional_adapters.ts +6 -193
@@ -17,7 +17,14 @@ import cloneDeep from 'lodash.clonedeep';
17
17
  type PreimageWitness<T extends IndexedTreeLeafPreimage> = {
18
18
  preimage: T;
19
19
  index: bigint;
20
- update: boolean;
20
+ };
21
+
22
+ /**
23
+ * The result of fetching a leaf from an indexed tree. Contains the preimage and wether the leaf was already present
24
+ * or it's a low leaf.
25
+ */
26
+ type GetLeafResult<T extends IndexedTreeLeafPreimage> = PreimageWitness<T> & {
27
+ alreadyPresent: boolean;
21
28
  };
22
29
 
23
30
  /**
@@ -29,16 +36,30 @@ type LeafWitness<T extends IndexedTreeLeafPreimage> = PreimageWitness<T> & {
29
36
  };
30
37
 
31
38
  /**
32
- * The result of an indexed insertion in an indexed merkle tree.
39
+ * The result of an update in an indexed merkle tree (no new leaf inserted)
40
+ */
41
+ type IndexedUpdateResult<T extends IndexedTreeLeafPreimage> = {
42
+ element: T;
43
+ lowWitness: LeafWitness<T>;
44
+ };
45
+
46
+ /**
47
+ * The result of an insertion in an indexed merkle tree.
33
48
  * This will be used to hint the circuit
34
49
  */
35
- export type IndexedInsertionResult<T extends IndexedTreeLeafPreimage> = {
50
+ export type IndexedInsertResult<T extends IndexedTreeLeafPreimage> = IndexedUpdateResult<T> & {
36
51
  leafIndex: bigint;
37
52
  insertionPath: Fr[];
38
- newOrElementToUpdate: { update: boolean; element: T };
39
- lowWitness: LeafWitness<T>;
40
53
  };
41
54
 
55
+ /**
56
+ * The result of an indexed upsert in an indexed merkle tree.
57
+ * This will be used to hint the circuit
58
+ */
59
+ export type IndexedUpsertResult<T extends IndexedTreeLeafPreimage> =
60
+ | (IndexedUpdateResult<T> & { update: true })
61
+ | (IndexedInsertResult<T> & { update: false });
62
+
42
63
  /****************************************************/
43
64
  /****** The AvmEphemeralForest Class ****************/
44
65
  /****************************************************/
@@ -144,7 +165,7 @@ export class AvmEphemeralForest {
144
165
  * @param newValue - The value to be written or updated to
145
166
  * @returns The insertion result which contains the insertion path, low leaf and the new leaf index
146
167
  */
147
- async writePublicStorage(slot: Fr, newValue: Fr): Promise<IndexedInsertionResult<PublicDataTreeLeafPreimage>> {
168
+ async writePublicStorage(slot: Fr, newValue: Fr): Promise<IndexedUpsertResult<PublicDataTreeLeafPreimage>> {
148
169
  // This only works for the public data tree
149
170
  const treeId = MerkleTreeId.PUBLIC_DATA_TREE;
150
171
  const tree = this.treeMap.get(treeId)!;
@@ -152,12 +173,12 @@ export class AvmEphemeralForest {
152
173
  typeof treeId,
153
174
  PublicDataTreeLeafPreimage
154
175
  >(treeId, slot);
155
- const { preimage, index, update } = leafOrLowLeafInfo;
156
- const siblingPath = await this.getSiblingPath(treeId, index);
176
+ const { preimage, index: lowLeafIndex, alreadyPresent: update } = leafOrLowLeafInfo;
177
+ const siblingPath = await this.getSiblingPath(treeId, lowLeafIndex);
157
178
 
158
179
  if (pathAbsentInEphemeralTree) {
159
180
  // Since we have never seen this before - we should insert it into our tree as it is about to be updated.
160
- this.treeMap.get(treeId)!.insertSiblingPath(index, siblingPath);
181
+ this.treeMap.get(treeId)!.insertSiblingPath(lowLeafIndex, siblingPath);
161
182
  }
162
183
 
163
184
  if (update) {
@@ -165,29 +186,18 @@ export class AvmEphemeralForest {
165
186
  const existingPublicDataSiblingPath = siblingPath;
166
187
  updatedPreimage.value = newValue;
167
188
 
168
- // It is really unintuitive that by updating, we are also appending a Zero Leaf to the tree
169
- // Additionally, this leaf preimage does not seem to factor into further appends
170
- const emptyLeaf = new PublicDataTreeLeafPreimage(Fr.ZERO, Fr.ZERO, Fr.ZERO, 0n);
171
- const insertionIndex = tree.leafCount;
172
- tree.updateLeaf(this.hashPreimage(updatedPreimage), index);
173
- tree.appendLeaf(Fr.ZERO);
174
- this.setIndexedUpdates(treeId, index, updatedPreimage);
175
- this.setIndexedUpdates(treeId, insertionIndex, emptyLeaf);
176
- const insertionPath = tree.getSiblingPath(insertionIndex)!;
177
-
178
- // Even though we append an empty leaf into the tree as a part of update - it doesnt seem to impact future inserts...
179
- this._updateSortedKeys(treeId, [updatedPreimage.slot], [index]);
189
+ tree.updateLeaf(this.hashPreimage(updatedPreimage), lowLeafIndex);
190
+ this.setIndexedUpdates(treeId, lowLeafIndex, updatedPreimage);
191
+ this._updateSortedKeys(treeId, [updatedPreimage.slot], [lowLeafIndex]);
180
192
 
181
193
  return {
182
- leafIndex: insertionIndex,
183
- insertionPath,
184
- newOrElementToUpdate: { update: true, element: updatedPreimage },
194
+ element: updatedPreimage,
185
195
  lowWitness: {
186
196
  preimage: preimage,
187
- index: index,
188
- update: true,
197
+ index: lowLeafIndex,
189
198
  siblingPath: existingPublicDataSiblingPath,
190
199
  },
200
+ update: true,
191
201
  };
192
202
  }
193
203
  // We are writing to a new slot, so our preimage is a lowNullifier
@@ -202,22 +212,22 @@ export class AvmEphemeralForest {
202
212
  new Fr(preimage.getNextKey()),
203
213
  preimage.getNextIndex(),
204
214
  );
205
- const insertionPath = this.appendIndexedTree(treeId, index, updatedLowLeaf, newPublicDataLeaf);
215
+ const insertionPath = this.appendIndexedTree(treeId, lowLeafIndex, updatedLowLeaf, newPublicDataLeaf);
206
216
 
207
217
  // Even though the low leaf key is not updated, we still need to update the sorted keys in case we have
208
218
  // not seen the low leaf before
209
- this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex, index]);
219
+ this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex, lowLeafIndex]);
210
220
 
211
221
  return {
212
- leafIndex: insertionIndex,
213
- insertionPath: insertionPath,
214
- newOrElementToUpdate: { update: false, element: newPublicDataLeaf },
222
+ element: newPublicDataLeaf,
215
223
  lowWitness: {
216
224
  preimage,
217
- index: index,
218
- update: false,
225
+ index: lowLeafIndex,
219
226
  siblingPath,
220
227
  },
228
+ update: false,
229
+ leafIndex: insertionIndex,
230
+ insertionPath: insertionPath,
221
231
  };
222
232
  }
223
233
 
@@ -247,14 +257,14 @@ export class AvmEphemeralForest {
247
257
  * @param value - The nullifier to be appended
248
258
  * @returns The insertion result which contains the insertion path, low leaf and the new leaf index
249
259
  */
250
- async appendNullifier(nullifier: Fr): Promise<IndexedInsertionResult<NullifierLeafPreimage>> {
260
+ async appendNullifier(nullifier: Fr): Promise<IndexedInsertResult<NullifierLeafPreimage>> {
251
261
  const treeId = MerkleTreeId.NULLIFIER_TREE;
252
262
  const tree = this.treeMap.get(treeId)!;
253
263
  const [leafOrLowLeafInfo, pathAbsentInEphemeralTree] = await this._getLeafOrLowLeafInfo<
254
264
  typeof treeId,
255
265
  NullifierLeafPreimage
256
266
  >(treeId, nullifier);
257
- const { preimage, index, update } = leafOrLowLeafInfo;
267
+ const { preimage, index, alreadyPresent } = leafOrLowLeafInfo;
258
268
  const siblingPath = await this.getSiblingPath(treeId, index);
259
269
 
260
270
  if (pathAbsentInEphemeralTree) {
@@ -262,7 +272,7 @@ export class AvmEphemeralForest {
262
272
  this.treeMap.get(treeId)!.insertSiblingPath(index, siblingPath);
263
273
  }
264
274
 
265
- assert(!update, 'Nullifier already exists in the tree. Cannot update a nullifier!');
275
+ assert(!alreadyPresent, 'Nullifier already exists in the tree. Cannot update a nullifier!');
266
276
 
267
277
  // We are writing a new entry
268
278
  const insertionIndex = tree.leafCount;
@@ -282,15 +292,14 @@ export class AvmEphemeralForest {
282
292
  );
283
293
 
284
294
  return {
285
- leafIndex: insertionIndex,
286
- insertionPath: insertionPath,
287
- newOrElementToUpdate: { update: false, element: newNullifierLeaf },
295
+ element: newNullifierLeaf,
288
296
  lowWitness: {
289
297
  preimage,
290
298
  index,
291
- update,
292
299
  siblingPath,
293
300
  },
301
+ leafIndex: insertionIndex,
302
+ insertionPath: insertionPath,
294
303
  };
295
304
  }
296
305
 
@@ -360,7 +369,7 @@ export class AvmEphemeralForest {
360
369
  async getLeafOrLowLeafInfo<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
361
370
  treeId: ID,
362
371
  key: Fr,
363
- ): Promise<PreimageWitness<T>> {
372
+ ): Promise<GetLeafResult<T>> {
364
373
  const [leafOrLowLeafInfo, _] = await this._getLeafOrLowLeafInfo<ID, T>(treeId, key);
365
374
  return leafOrLowLeafInfo;
366
375
  }
@@ -373,14 +382,14 @@ export class AvmEphemeralForest {
373
382
  * @param key - The key for which we are look up the leaf or low leaf for.
374
383
  * @param T - The type of the preimage (PublicData or Nullifier)
375
384
  * @returns [
376
- * preimageWitness - The leaf or low leaf info (preimage & leaf index),
385
+ * getLeafResult - The leaf or low leaf info (preimage & leaf index),
377
386
  * pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions)
378
387
  * ]
379
388
  */
380
389
  async _getLeafOrLowLeafInfo<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
381
390
  treeId: ID,
382
391
  key: Fr,
383
- ): Promise<[PreimageWitness<T>, /*pathAbsentInEphemeralTree=*/ boolean]> {
392
+ ): Promise<[GetLeafResult<T>, /*pathAbsentInEphemeralTree=*/ boolean]> {
384
393
  const bigIntKey = key.toBigInt();
385
394
  // In this function, "min" refers to the leaf with the
386
395
  // largest key <= the specified key in the indexedUpdates.
@@ -392,7 +401,7 @@ export class AvmEphemeralForest {
392
401
  if (minIndexedLeafIndex === -1n) {
393
402
  // No leaf is present in the indexed updates that is <= the key,
394
403
  // so retrieve the leaf or low leaf from the underlying DB.
395
- const leafOrLowLeafPreimage: PreimageWitness<T> = await this._getLeafOrLowLeafWitnessInExternalDb(
404
+ const leafOrLowLeafPreimage: GetLeafResult<T> = await this._getLeafOrLowLeafWitnessInExternalDb(
396
405
  treeId,
397
406
  bigIntKey,
398
407
  );
@@ -402,7 +411,7 @@ export class AvmEphemeralForest {
402
411
  const minPreimage: T = this.getIndexedUpdate(treeId, minIndexedLeafIndex);
403
412
  if (minPreimage.getKey() === bigIntKey) {
404
413
  // the index found is an exact match, no need to search further
405
- const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex, update: true };
414
+ const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex, alreadyPresent: true };
406
415
  return [leafInfo, /*pathAbsentInEphemeralTree=*/ false];
407
416
  } else {
408
417
  // We are starting with the leaf with largest key <= the specified key
@@ -453,7 +462,7 @@ export class AvmEphemeralForest {
453
462
  private async _getLeafOrLowLeafWitnessInExternalDb<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
454
463
  treeId: ID,
455
464
  key: bigint,
456
- ): Promise<PreimageWitness<T>> {
465
+ ): Promise<GetLeafResult<T>> {
457
466
  // "key" is siloed slot (leafSlot) or siloed nullifier
458
467
  const previousValueIndex = await this.treeDb.getPreviousValueIndex(treeId, key);
459
468
  assert(
@@ -468,7 +477,7 @@ export class AvmEphemeralForest {
468
477
  `${MerkleTreeId[treeId]} low leaf preimage should never be undefined (even if target leaf does not exist)`,
469
478
  );
470
479
 
471
- return { preimage: leafPreimage as T, index: leafIndex, update: alreadyPresent };
480
+ return { preimage: leafPreimage as T, index: leafIndex, alreadyPresent };
472
481
  }
473
482
 
474
483
  /**
@@ -481,7 +490,7 @@ export class AvmEphemeralForest {
481
490
  * @param minIndex - The index of the leaf with the largest key <= the specified key.
482
491
  * @param T - The type of the preimage (PublicData or Nullifier)
483
492
  * @returns [
484
- * preimageWitness | undefined - The leaf or low leaf info (preimage & leaf index),
493
+ * GetLeafResult | undefined - The leaf or low leaf info (preimage & leaf index),
485
494
  * pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions)
486
495
  * ]
487
496
  *
@@ -497,10 +506,10 @@ export class AvmEphemeralForest {
497
506
  key: bigint,
498
507
  minPreimage: T,
499
508
  minIndex: bigint,
500
- ): Promise<[PreimageWitness<T> | undefined, /*pathAbsentInEphemeralTree=*/ boolean]> {
509
+ ): Promise<[GetLeafResult<T> | undefined, /*pathAbsentInEphemeralTree=*/ boolean]> {
501
510
  let found = false;
502
511
  let curr = minPreimage as T;
503
- let result: PreimageWitness<T> | undefined = undefined;
512
+ let result: GetLeafResult<T> | undefined = undefined;
504
513
  // Temp to avoid infinite loops - the limit is the number of leaves we may have to read
505
514
  const LIMIT = 2n ** BigInt(getTreeHeight(treeId)) - 1n;
506
515
  let counter = 0n;
@@ -511,11 +520,11 @@ export class AvmEphemeralForest {
511
520
  if (curr.getKey() === bigIntKey) {
512
521
  // We found an exact match - therefore this is an update
513
522
  found = true;
514
- result = { preimage: curr, index: lowPublicDataIndex, update: true };
523
+ result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: true };
515
524
  } else if (curr.getKey() < bigIntKey && (curr.getNextIndex() === 0n || curr.getNextKey() > bigIntKey)) {
516
525
  // We found it via sandwich or max condition, this is a low nullifier
517
526
  found = true;
518
- result = { preimage: curr, index: lowPublicDataIndex, update: false };
527
+ result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: false };
519
528
  }
520
529
  // Update the the values for the next iteration
521
530
  else {
@@ -671,7 +680,12 @@ export class EphemeralAvmTree {
671
680
  for (let i = 0; i < siblingPath.length; i++) {
672
681
  // Flip(XOR) the last bit because we are inserting siblings of the leaf
673
682
  const sibIndex = index ^ 1n;
674
- this.updateLeaf(siblingPath[i], sibIndex, this.depth - i);
683
+ const node = this.getNode(sibIndex, this.depth - i);
684
+ // If we are inserting a sibling path and we already have a branch at that index in our
685
+ // ephemeral tree, we should not overwrite it
686
+ if (node === undefined || node.tag === TreeType.LEAF) {
687
+ this.updateLeaf(siblingPath[i], sibIndex, this.depth - i);
688
+ }
675
689
  index >>= 1n;
676
690
  }
677
691
  }
@@ -163,8 +163,12 @@ export class AvmPersistableStateManager {
163
163
  const lowLeafIndex = lowLeafInfo.index;
164
164
  const lowLeafPath = lowLeafInfo.siblingPath;
165
165
 
166
- const insertionPath = result.insertionPath;
167
- const newLeafPreimage = result.newOrElementToUpdate.element as PublicDataTreeLeafPreimage;
166
+ const newLeafPreimage = result.element as PublicDataTreeLeafPreimage;
167
+ let insertionPath;
168
+
169
+ if (!result.update) {
170
+ insertionPath = result.insertionPath;
171
+ }
168
172
 
169
173
  this.trace.tracePublicStorageWrite(
170
174
  contractAddress,
@@ -200,7 +204,7 @@ export class AvmPersistableStateManager {
200
204
  const {
201
205
  preimage,
202
206
  index: leafIndex,
203
- update: exists,
207
+ alreadyPresent,
204
208
  } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
205
209
  // The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag)
206
210
  // In either case, we just want the sibling path to this leaf - it's up to the avm to distinguish if it's a low leaf or not
@@ -212,7 +216,7 @@ export class AvmPersistableStateManager {
212
216
  );
213
217
  this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
214
218
 
215
- if (!exists) {
219
+ if (!alreadyPresent) {
216
220
  // Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
217
221
  assert(
218
222
  leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
@@ -308,12 +312,15 @@ export class AvmPersistableStateManager {
308
312
  const {
309
313
  preimage,
310
314
  index: leafIndex,
311
- update,
315
+ alreadyPresent,
312
316
  } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.NULLIFIER_TREE, siloedNullifier);
313
317
  const leafPreimage = preimage as NullifierLeafPreimage;
314
318
  const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
315
319
 
316
- assert(update == exists, 'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!');
320
+ assert(
321
+ alreadyPresent == exists,
322
+ 'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!',
323
+ );
317
324
 
318
325
  if (exists) {
319
326
  this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`);
@@ -355,11 +362,11 @@ export class AvmPersistableStateManager {
355
362
  // Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert
356
363
  // It might be better to catch the error from the insert operation
357
364
  // Trace all nullifier creations, even duplicate insertions that fail
358
- const { preimage, index, update } = await this.merkleTrees.getLeafOrLowLeafInfo(
365
+ const { preimage, index, alreadyPresent } = await this.merkleTrees.getLeafOrLowLeafInfo(
359
366
  MerkleTreeId.NULLIFIER_TREE,
360
367
  siloedNullifier,
361
368
  );
362
- if (update) {
369
+ if (alreadyPresent) {
363
370
  this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`);
364
371
  // If the nullifier is already present, we should not insert it again
365
372
  // instead we provide the direct membership path
@@ -367,7 +374,7 @@ export class AvmPersistableStateManager {
367
374
  // This just becomes a nullifier read hint
368
375
  this.trace.traceNullifierCheck(
369
376
  siloedNullifier,
370
- /*exists=*/ update,
377
+ /*exists=*/ alreadyPresent,
371
378
  preimage as NullifierLeafPreimage,
372
379
  new Fr(index),
373
380
  path,
@@ -379,6 +386,11 @@ export class AvmPersistableStateManager {
379
386
  // Cache pending nullifiers for later access
380
387
  await this.nullifiers.append(siloedNullifier);
381
388
  // We append the new nullifier
389
+ this.log.debug(
390
+ `Nullifier tree root before insertion ${this.merkleTrees.treeMap
391
+ .get(MerkleTreeId.NULLIFIER_TREE)!
392
+ .getRoot()}`,
393
+ );
382
394
  const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier);
383
395
  this.log.debug(
384
396
  `Nullifier tree root after insertion ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
@@ -1,5 +1,5 @@
1
1
  import type { AvmContext } from '../avm_context.js';
2
- import { Field, Uint32, Uint64 } from '../avm_memory_types.js';
2
+ import { Field, Uint64 } from '../avm_memory_types.js';
3
3
  import { InstructionExecutionError } from '../errors.js';
4
4
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
5
5
  import { Addressing } from './addressing_mode.js';
@@ -8,7 +8,6 @@ import { Instruction } from './instruction.js';
8
8
  export enum EnvironmentVariable {
9
9
  ADDRESS,
10
10
  SENDER,
11
- FUNCTIONSELECTOR,
12
11
  TRANSACTIONFEE,
13
12
  CHAINID,
14
13
  VERSION,
@@ -27,8 +26,6 @@ function getValue(e: EnvironmentVariable, ctx: AvmContext) {
27
26
  return new Field(ctx.environment.address.toField());
28
27
  case EnvironmentVariable.SENDER:
29
28
  return new Field(ctx.environment.sender.toField());
30
- case EnvironmentVariable.FUNCTIONSELECTOR:
31
- return new Uint32(ctx.environment.functionSelector.value);
32
29
  case EnvironmentVariable.TRANSACTIONFEE:
33
30
  return new Field(ctx.environment.transactionFee);
34
31
  case EnvironmentVariable.CHAINID:
@@ -1,11 +1,8 @@
1
1
  import {
2
2
  type AuthWitness,
3
3
  type AztecNode,
4
- CountedLog,
5
- CountedNoteLog,
4
+ CountedContractClassLog,
6
5
  CountedPublicExecutionRequest,
7
- EncryptedL2Log,
8
- EncryptedL2NoteLog,
9
6
  Note,
10
7
  NoteAndSlot,
11
8
  type NoteStatus,
@@ -25,7 +22,6 @@ import {
25
22
  import { computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
26
23
  import { type FunctionAbi, type FunctionArtifact, type NoteSelector, countArgumentsSize } from '@aztec/foundation/abi';
27
24
  import { AztecAddress } from '@aztec/foundation/aztec-address';
28
- import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
29
25
  import { Fr } from '@aztec/foundation/fields';
30
26
  import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log';
31
27
 
@@ -60,9 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle {
60
56
  */
61
57
  private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
62
58
  private noteHashNullifierCounterMap: Map<number, number> = new Map();
63
- private noteEncryptedLogs: CountedNoteLog[] = [];
64
- private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
65
- private contractClassLogs: CountedLog<UnencryptedL2Log>[] = [];
59
+ private contractClassLogs: CountedContractClassLog[] = [];
66
60
  private nestedExecutions: PrivateExecutionResult[] = [];
67
61
  private enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[] = [];
68
62
  private publicTeardownFunctionCall: PublicExecutionRequest = PublicExecutionRequest.empty();
@@ -136,20 +130,6 @@ export class ClientExecutionContext extends ViewDataOracle {
136
130
  return this.noteHashNullifierCounterMap;
137
131
  }
138
132
 
139
- /**
140
- * Return the note encrypted logs emitted during this execution.
141
- */
142
- public getNoteEncryptedLogs() {
143
- return this.noteEncryptedLogs;
144
- }
145
-
146
- /**
147
- * Return the encrypted logs emitted during this execution.
148
- */
149
- public getEncryptedLogs() {
150
- return this.encryptedLogs;
151
- }
152
-
153
133
  /**
154
134
  * Return the contract class logs emitted during this execution.
155
135
  */
@@ -326,49 +306,15 @@ export class ClientExecutionContext extends ViewDataOracle {
326
306
  return Promise.resolve();
327
307
  }
328
308
 
329
- /**
330
- * Emit encrypted data
331
- * @param contractAddress - The contract emitting the encrypted event.
332
- * @param randomness - A value used to mask the contract address we are siloing with.
333
- * @param encryptedEvent - The encrypted event data.
334
- * @param counter - The effects counter.
335
- */
336
- public override emitEncryptedEventLog(
337
- contractAddress: AztecAddress,
338
- randomness: Fr,
339
- encryptedEvent: Buffer,
340
- counter: number,
341
- ) {
342
- // In some cases, we actually want to reveal the contract address we are siloing with:
343
- // e.g. 'handshaking' contract w/ known address
344
- // An app providing randomness = 0 signals to not mask the address.
345
- const maskedContractAddress = randomness.isZero()
346
- ? contractAddress.toField()
347
- : poseidon2HashWithSeparator([contractAddress, randomness], 0);
348
- const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedEvent, maskedContractAddress), counter);
349
- this.encryptedLogs.push(encryptedLog);
350
- }
351
-
352
- /**
353
- * Emit encrypted note data
354
- * @param noteHashCounter - The note hash counter.
355
- * @param encryptedNote - The encrypted note data.
356
- * @param counter - The log counter.
357
- */
358
- public override emitEncryptedNoteLog(noteHashCounter: number, encryptedNote: Buffer, counter: number) {
359
- const encryptedLog = new CountedNoteLog(new EncryptedL2NoteLog(encryptedNote), counter, noteHashCounter);
360
- this.noteEncryptedLogs.push(encryptedLog);
361
- }
362
-
363
309
  /**
364
310
  * Emit a contract class unencrypted log.
365
- * This fn exists separately from emitUnencryptedLog because sha hashing the preimage
311
+ * This fn exists because sha hashing the preimage
366
312
  * is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it.
367
313
  * See private_context.nr
368
314
  * @param log - The unencrypted log to be emitted.
369
315
  */
370
316
  public override emitContractClassLog(log: UnencryptedL2Log, counter: number) {
371
- this.contractClassLogs.push(new CountedLog(log, counter));
317
+ this.contractClassLogs.push(new CountedContractClassLog(log, counter));
372
318
  const text = log.toHumanReadable();
373
319
  this.log.verbose(
374
320
  `Emitted log from ContractClassRegisterer: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`,
@@ -381,7 +327,7 @@ export class ClientExecutionContext extends ViewDataOracle {
381
327
  childExecutionResult.publicInputs.noteHashes.some(item => !item.isEmpty()) ||
382
328
  childExecutionResult.publicInputs.nullifiers.some(item => !item.isEmpty()) ||
383
329
  childExecutionResult.publicInputs.l2ToL1Msgs.some(item => !item.isEmpty()) ||
384
- childExecutionResult.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) ||
330
+ childExecutionResult.publicInputs.privateLogs.some(item => !item.isEmpty()) ||
385
331
  childExecutionResult.publicInputs.contractClassLogsHashes.some(item => !item.isEmpty())
386
332
  ) {
387
333
  throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`);
@@ -59,8 +59,6 @@ export async function executePrivateFunction(
59
59
  appCircuitName: functionName,
60
60
  } satisfies CircuitWitnessGenerationStats);
61
61
 
62
- const noteEncryptedLogs = context.getNoteEncryptedLogs();
63
- const encryptedLogs = context.getEncryptedLogs();
64
62
  const contractClassLogs = context.getContractClassLogs();
65
63
 
66
64
  const rawReturnValues = await context.unpackReturns(publicInputs.returnsHash);
@@ -86,8 +84,6 @@ export async function executePrivateFunction(
86
84
  nestedExecutions,
87
85
  enqueuedPublicFunctionCalls,
88
86
  publicTeardownFunctionCall,
89
- noteEncryptedLogs,
90
- encryptedLogs,
91
87
  contractClassLogs,
92
88
  );
93
89
  }
@@ -179,15 +179,13 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
179
179
  this.avmCircuitHints.contractInstances.items.push(...forkedTrace.avmCircuitHints.contractInstances.items);
180
180
  this.avmCircuitHints.contractBytecodeHints.items.push(...forkedTrace.avmCircuitHints.contractBytecodeHints.items);
181
181
 
182
- this.avmCircuitHints.storageReadRequest.items.push(...forkedTrace.avmCircuitHints.storageReadRequest.items);
183
- this.avmCircuitHints.storageUpdateRequest.items.push(...forkedTrace.avmCircuitHints.storageUpdateRequest.items);
184
- this.avmCircuitHints.nullifierReadRequest.items.push(...forkedTrace.avmCircuitHints.nullifierReadRequest.items);
185
- this.avmCircuitHints.nullifierWriteHints.items.push(...forkedTrace.avmCircuitHints.nullifierWriteHints.items);
186
- this.avmCircuitHints.noteHashReadRequest.items.push(...forkedTrace.avmCircuitHints.noteHashReadRequest.items);
187
- this.avmCircuitHints.noteHashWriteRequest.items.push(...forkedTrace.avmCircuitHints.noteHashWriteRequest.items);
188
- this.avmCircuitHints.l1ToL2MessageReadRequest.items.push(
189
- ...forkedTrace.avmCircuitHints.l1ToL2MessageReadRequest.items,
190
- );
182
+ this.avmCircuitHints.publicDataReads.items.push(...forkedTrace.avmCircuitHints.publicDataReads.items);
183
+ this.avmCircuitHints.publicDataWrites.items.push(...forkedTrace.avmCircuitHints.publicDataWrites.items);
184
+ this.avmCircuitHints.nullifierReads.items.push(...forkedTrace.avmCircuitHints.nullifierReads.items);
185
+ this.avmCircuitHints.nullifierWrites.items.push(...forkedTrace.avmCircuitHints.nullifierWrites.items);
186
+ this.avmCircuitHints.noteHashReads.items.push(...forkedTrace.avmCircuitHints.noteHashReads.items);
187
+ this.avmCircuitHints.noteHashWrites.items.push(...forkedTrace.avmCircuitHints.noteHashWrites.items);
188
+ this.avmCircuitHints.l1ToL2MessageReads.items.push(...forkedTrace.avmCircuitHints.l1ToL2MessageReads.items);
191
189
  }
192
190
 
193
191
  public getCounter() {
@@ -211,7 +209,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
211
209
  assert(leafPreimage.value.equals(value), 'Value mismatch when tracing in public data write');
212
210
  }
213
211
 
214
- this.avmCircuitHints.storageReadRequest.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path));
212
+ this.avmCircuitHints.publicDataReads.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path));
215
213
  this.log.debug(`SLOAD cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`);
216
214
  this.incrementSideEffectCounter();
217
215
  }
@@ -245,7 +243,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
245
243
 
246
244
  // New hinting
247
245
  const readHint = new AvmPublicDataReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
248
- this.avmCircuitHints.storageUpdateRequest.items.push(
246
+ this.avmCircuitHints.publicDataWrites.items.push(
249
247
  new AvmPublicDataWriteTreeHint(readHint, newLeafPreimage, insertionPath),
250
248
  );
251
249
 
@@ -264,7 +262,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
264
262
  path: Fr[] = emptyNoteHashPath(),
265
263
  ) {
266
264
  // New Hinting
267
- this.avmCircuitHints.noteHashReadRequest.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
265
+ this.avmCircuitHints.noteHashReads.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
268
266
  // NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes)
269
267
  }
270
268
 
@@ -282,7 +280,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
282
280
  //const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
283
281
  this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter).scope(contractAddress));
284
282
  this.log.debug(`NEW_NOTE_HASH cnt: ${this.sideEffectCounter}`);
285
- this.avmCircuitHints.noteHashWriteRequest.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
283
+ this.avmCircuitHints.noteHashWrites.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
286
284
  this.incrementSideEffectCounter();
287
285
  }
288
286
 
@@ -293,7 +291,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
293
291
  lowLeafIndex: Fr = Fr.zero(),
294
292
  lowLeafPath: Fr[] = emptyNullifierPath(),
295
293
  ) {
296
- this.avmCircuitHints.nullifierReadRequest.items.push(
294
+ this.avmCircuitHints.nullifierReads.items.push(
297
295
  new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath),
298
296
  );
299
297
  this.log.debug(`NULLIFIER_EXISTS cnt: ${this.sideEffectCounter}`);
@@ -314,7 +312,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
314
312
  this.nullifiers.push(new Nullifier(siloedNullifier, this.sideEffectCounter, /*noteHash=*/ Fr.ZERO));
315
313
 
316
314
  const lowLeafReadHint = new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
317
- this.avmCircuitHints.nullifierWriteHints.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath));
315
+ this.avmCircuitHints.nullifierWrites.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath));
318
316
  this.log.debug(`NEW_NULLIFIER cnt: ${this.sideEffectCounter}`);
319
317
  this.incrementSideEffectCounter();
320
318
  }
@@ -327,7 +325,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
327
325
  _exists: boolean,
328
326
  path: Fr[] = emptyL1ToL2MessagePath(),
329
327
  ) {
330
- this.avmCircuitHints.l1ToL2MessageReadRequest.items.push(new AvmAppendTreeHint(msgLeafIndex, msgHash, path));
328
+ this.avmCircuitHints.l1ToL2MessageReads.items.push(new AvmAppendTreeHint(msgLeafIndex, msgHash, path));
331
329
  }
332
330
 
333
331
  public traceNewL2ToL1Message(contractAddress: AztecAddress, recipient: Fr, content: Fr) {