@aztec/simulator 0.65.2 → 0.67.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 (136) hide show
  1. package/dest/acvm/acvm.js +3 -3
  2. package/dest/acvm/oracle/oracle.d.ts +1 -4
  3. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  4. package/dest/acvm/oracle/oracle.js +3 -19
  5. package/dest/acvm/oracle/typed_oracle.d.ts +2 -7
  6. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  7. package/dest/acvm/oracle/typed_oracle.js +3 -12
  8. package/dest/acvm/serialize.js +2 -2
  9. package/dest/avm/avm_context.d.ts +2 -2
  10. package/dest/avm/avm_context.d.ts.map +1 -1
  11. package/dest/avm/avm_context.js +3 -4
  12. package/dest/avm/avm_execution_environment.d.ts +4 -6
  13. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  14. package/dest/avm/avm_execution_environment.js +8 -13
  15. package/dest/avm/avm_memory_types.d.ts +2 -2
  16. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  17. package/dest/avm/avm_memory_types.js +7 -7
  18. package/dest/avm/avm_simulator.d.ts +3 -3
  19. package/dest/avm/avm_simulator.d.ts.map +1 -1
  20. package/dest/avm/avm_simulator.js +26 -16
  21. package/dest/avm/avm_tree.d.ts +31 -14
  22. package/dest/avm/avm_tree.d.ts.map +1 -1
  23. package/dest/avm/avm_tree.js +34 -40
  24. package/dest/avm/errors.d.ts +3 -3
  25. package/dest/avm/errors.d.ts.map +1 -1
  26. package/dest/avm/errors.js +8 -15
  27. package/dest/avm/fixtures/index.d.ts.map +1 -1
  28. package/dest/avm/fixtures/index.js +4 -4
  29. package/dest/avm/journal/journal.d.ts +15 -4
  30. package/dest/avm/journal/journal.d.ts.map +1 -1
  31. package/dest/avm/journal/journal.js +121 -36
  32. package/dest/avm/opcodes/environment_getters.d.ts +10 -11
  33. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  34. package/dest/avm/opcodes/environment_getters.js +12 -15
  35. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  36. package/dest/avm/opcodes/external_calls.js +4 -11
  37. package/dest/avm/opcodes/misc.d.ts.map +1 -1
  38. package/dest/avm/opcodes/misc.js +3 -3
  39. package/dest/client/client_execution_context.d.ts +6 -33
  40. package/dest/client/client_execution_context.d.ts.map +1 -1
  41. package/dest/client/client_execution_context.js +18 -54
  42. package/dest/client/db_oracle.d.ts +2 -2
  43. package/dest/client/db_oracle.d.ts.map +1 -1
  44. package/dest/client/execution_note_cache.d.ts +9 -1
  45. package/dest/client/execution_note_cache.d.ts.map +1 -1
  46. package/dest/client/execution_note_cache.js +10 -3
  47. package/dest/client/private_execution.d.ts.map +1 -1
  48. package/dest/client/private_execution.js +5 -7
  49. package/dest/client/simulator.d.ts.map +1 -1
  50. package/dest/client/simulator.js +4 -4
  51. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  52. package/dest/client/unconstrained_execution.js +3 -3
  53. package/dest/client/view_data_oracle.d.ts +2 -2
  54. package/dest/client/view_data_oracle.d.ts.map +1 -1
  55. package/dest/client/view_data_oracle.js +5 -6
  56. package/dest/common/debug_fn_name.d.ts +2 -2
  57. package/dest/common/debug_fn_name.d.ts.map +1 -1
  58. package/dest/common/debug_fn_name.js +8 -14
  59. package/dest/providers/acvm_native.js +4 -4
  60. package/dest/providers/factory.d.ts +2 -2
  61. package/dest/providers/factory.d.ts.map +1 -1
  62. package/dest/providers/factory.js +4 -4
  63. package/dest/public/enqueued_call_side_effect_trace.d.ts +11 -23
  64. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  65. package/dest/public/enqueued_call_side_effect_trace.js +51 -72
  66. package/dest/public/executor_metrics.d.ts.map +1 -1
  67. package/dest/public/executor_metrics.js +2 -5
  68. package/dest/public/fixtures/index.d.ts +25 -7
  69. package/dest/public/fixtures/index.d.ts.map +1 -1
  70. package/dest/public/fixtures/index.js +20 -17
  71. package/dest/public/index.d.ts +0 -1
  72. package/dest/public/index.d.ts.map +1 -1
  73. package/dest/public/index.js +1 -2
  74. package/dest/public/public_db_sources.d.ts.map +1 -1
  75. package/dest/public/public_db_sources.js +30 -16
  76. package/dest/public/public_processor.d.ts +7 -8
  77. package/dest/public/public_processor.d.ts.map +1 -1
  78. package/dest/public/public_processor.js +37 -26
  79. package/dest/public/public_processor_metrics.d.ts +1 -1
  80. package/dest/public/public_processor_metrics.d.ts.map +1 -1
  81. package/dest/public/public_tx_context.d.ts +13 -14
  82. package/dest/public/public_tx_context.d.ts.map +1 -1
  83. package/dest/public/public_tx_context.js +63 -54
  84. package/dest/public/public_tx_simulator.d.ts +2 -2
  85. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  86. package/dest/public/public_tx_simulator.js +43 -25
  87. package/dest/public/side_effect_trace_interface.d.ts +4 -17
  88. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  89. package/dest/public/transitional_adapters.d.ts +2 -6
  90. package/dest/public/transitional_adapters.d.ts.map +1 -1
  91. package/dest/public/transitional_adapters.js +29 -88
  92. package/package.json +16 -9
  93. package/src/acvm/acvm.ts +2 -2
  94. package/src/acvm/oracle/oracle.ts +2 -32
  95. package/src/acvm/oracle/typed_oracle.ts +3 -20
  96. package/src/acvm/serialize.ts +1 -1
  97. package/src/avm/avm_context.ts +2 -3
  98. package/src/avm/avm_execution_environment.ts +6 -31
  99. package/src/avm/avm_memory_types.ts +6 -6
  100. package/src/avm/avm_simulator.ts +28 -23
  101. package/src/avm/avm_tree.ts +67 -53
  102. package/src/avm/errors.ts +12 -14
  103. package/src/avm/fixtures/index.ts +2 -3
  104. package/src/avm/journal/journal.ts +206 -68
  105. package/src/avm/opcodes/environment_getters.ts +1 -4
  106. package/src/avm/opcodes/external_calls.ts +3 -19
  107. package/src/avm/opcodes/misc.ts +2 -2
  108. package/src/client/client_execution_context.ts +22 -68
  109. package/src/client/db_oracle.ts +2 -2
  110. package/src/client/execution_note_cache.ts +13 -3
  111. package/src/client/private_execution.ts +3 -7
  112. package/src/client/simulator.ts +4 -4
  113. package/src/client/unconstrained_execution.ts +2 -2
  114. package/src/client/view_data_oracle.ts +5 -6
  115. package/src/common/debug_fn_name.ts +7 -13
  116. package/src/providers/acvm_native.ts +3 -3
  117. package/src/providers/factory.ts +3 -3
  118. package/src/public/enqueued_call_side_effect_trace.ts +68 -90
  119. package/src/public/executor_metrics.ts +0 -4
  120. package/src/public/fixtures/index.ts +28 -17
  121. package/src/public/index.ts +0 -1
  122. package/src/public/public_db_sources.ts +32 -19
  123. package/src/public/public_processor.ts +52 -55
  124. package/src/public/public_processor_metrics.ts +1 -1
  125. package/src/public/public_tx_context.ts +89 -76
  126. package/src/public/public_tx_simulator.ts +58 -49
  127. package/src/public/side_effect_trace_interface.ts +8 -15
  128. package/src/public/transitional_adapters.ts +43 -215
  129. package/dest/public/dual_side_effect_trace.d.ts +0 -77
  130. package/dest/public/dual_side_effect_trace.d.ts.map +0 -1
  131. package/dest/public/dual_side_effect_trace.js +0 -119
  132. package/dest/public/side_effect_trace.d.ts +0 -96
  133. package/dest/public/side_effect_trace.d.ts.map +0 -1
  134. package/dest/public/side_effect_trace.js +0 -309
  135. package/src/public/dual_side_effect_trace.ts +0 -242
  136. package/src/public/side_effect_trace.ts +0 -536
@@ -1,23 +1,27 @@
1
1
  import { MerkleTreeId } from '@aztec/circuit-types';
2
2
  import {
3
- type AztecAddress,
4
- type Gas,
5
- type NullifierLeafPreimage,
3
+ AztecAddress,
4
+ CANONICAL_AUTH_REGISTRY_ADDRESS,
5
+ DEPLOYER_CONTRACT_ADDRESS,
6
+ FEE_JUICE_ADDRESS,
7
+ MULTI_CALL_ENTRYPOINT_ADDRESS,
8
+ NullifierLeafPreimage,
6
9
  type PublicCallRequest,
7
10
  type PublicDataTreeLeafPreimage,
11
+ REGISTERER_CONTRACT_ADDRESS,
12
+ ROUTER_ADDRESS,
8
13
  SerializableContractInstance,
9
14
  } from '@aztec/circuits.js';
10
15
  import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
11
16
  import { Fr } from '@aztec/foundation/fields';
12
17
  import { jsonStringify } from '@aztec/foundation/json-rpc';
13
- import { createDebugLogger } from '@aztec/foundation/log';
18
+ import { createLogger } from '@aztec/foundation/log';
14
19
 
15
20
  import { strict as assert } from 'assert';
16
21
 
17
22
  import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
18
23
  import { type WorldStateDB } from '../../public/public_db_sources.js';
19
24
  import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
20
- import { type AvmContractCallResult } from '../avm_contract_call_result.js';
21
25
  import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
22
26
  import { AvmEphemeralForest } from '../avm_tree.js';
23
27
  import { NullifierCollisionError, NullifierManager } from './nullifiers.js';
@@ -33,7 +37,7 @@ import { PublicStorage } from './public_storage.js';
33
37
  * Manages merging of successful/reverted child state into current state.
34
38
  */
35
39
  export class AvmPersistableStateManager {
36
- private readonly log = createDebugLogger('aztec:avm_simulator:state_manager');
40
+ private readonly log = createLogger('simulator:avm:state_manager');
37
41
 
38
42
  /** Make sure a forked state is never merged twice. */
39
43
  private alreadyMergedIntoParent = false;
@@ -148,14 +152,16 @@ export class AvmPersistableStateManager {
148
152
  * @param slot - the slot in the contract's storage being written to
149
153
  * @param value - the value being written to the slot
150
154
  */
151
- public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr): Promise<void> {
155
+ public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr, protocolWrite = false): Promise<void> {
152
156
  this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
157
+ const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
158
+ this.log.debug(`leafSlot=${leafSlot}`);
153
159
  // Cache storage writes for later reference/reads
154
160
  this.publicStorage.write(contractAddress, slot, value);
155
- const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
161
+
156
162
  if (this.doMerkleOperations) {
157
163
  const result = await this.merkleTrees.writePublicStorage(leafSlot, value);
158
- assert(result !== undefined, 'Public data tree insertion error. You might want to disable skipMerkleOperations.');
164
+ assert(result !== undefined, 'Public data tree insertion error. You might want to disable doMerkleOperations.');
159
165
  this.log.debug(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`);
160
166
 
161
167
  const lowLeafInfo = result.lowWitness;
@@ -163,13 +169,21 @@ export class AvmPersistableStateManager {
163
169
  const lowLeafIndex = lowLeafInfo.index;
164
170
  const lowLeafPath = lowLeafInfo.siblingPath;
165
171
 
166
- const insertionPath = result.insertionPath;
167
- const newLeafPreimage = result.newOrElementToUpdate.element as PublicDataTreeLeafPreimage;
172
+ const newLeafPreimage = result.element as PublicDataTreeLeafPreimage;
173
+ let insertionPath: Fr[] | undefined;
174
+ if (!result.update) {
175
+ insertionPath = result.insertionPath;
176
+ assert(
177
+ newLeafPreimage.value.equals(value),
178
+ `Value mismatch when performing public data write (got value: ${value}, value in ephemeral tree: ${newLeafPreimage.value})`,
179
+ );
180
+ }
168
181
 
169
182
  this.trace.tracePublicStorageWrite(
170
183
  contractAddress,
171
184
  slot,
172
185
  value,
186
+ protocolWrite,
173
187
  lowLeafPreimage,
174
188
  new Fr(lowLeafIndex),
175
189
  lowLeafPath,
@@ -177,7 +191,7 @@ export class AvmPersistableStateManager {
177
191
  insertionPath,
178
192
  );
179
193
  } else {
180
- this.trace.tracePublicStorageWrite(contractAddress, slot, value);
194
+ this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
181
195
  }
182
196
  }
183
197
 
@@ -191,8 +205,8 @@ export class AvmPersistableStateManager {
191
205
  public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
192
206
  const { value, cached } = await this.publicStorage.read(contractAddress, slot);
193
207
  this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`);
194
-
195
208
  const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
209
+ this.log.debug(`leafSlot=${leafSlot}`);
196
210
 
197
211
  if (this.doMerkleOperations) {
198
212
  // Get leaf if present, low leaf if absent
@@ -200,19 +214,25 @@ export class AvmPersistableStateManager {
200
214
  const {
201
215
  preimage,
202
216
  index: leafIndex,
203
- update: exists,
217
+ alreadyPresent,
204
218
  } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
205
219
  // The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag)
206
220
  // 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
207
221
  const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
208
222
  const leafPreimage = preimage as PublicDataTreeLeafPreimage;
209
223
 
224
+ this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
210
225
  this.log.debug(
211
226
  `leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`,
212
227
  );
213
- this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
214
228
 
215
- if (!exists) {
229
+ if (alreadyPresent) {
230
+ assert(
231
+ leafPreimage.value.equals(value),
232
+ `Value mismatch when performing public data read (got value: ${value}, value in ephemeral tree: ${leafPreimage.value})`,
233
+ );
234
+ } else {
235
+ this.log.debug(`Slot has never been written before!`);
216
236
  // Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
217
237
  assert(
218
238
  leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
@@ -220,9 +240,6 @@ export class AvmPersistableStateManager {
220
240
  'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist or is the max value.',
221
241
  );
222
242
  }
223
- this.log.debug(
224
- `Tracing storage leaf preimage slot=${slot}, leafSlot=${leafSlot}, value=${value}, nextKey=${leafPreimage.nextSlot}, nextIndex=${leafPreimage.nextIndex}`,
225
- );
226
243
  // On non-existence, AVM circuit will need to recognize that leafPreimage.slot != leafSlot,
227
244
  // prove that this is a low leaf that skips leafSlot, and then prove membership of the leaf.
228
245
  this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, new Fr(leafIndex), leafPath);
@@ -299,8 +316,47 @@ export class AvmPersistableStateManager {
299
316
  public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise<boolean> {
300
317
  this.log.debug(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`);
301
318
  const siloedNullifier = siloNullifier(contractAddress, nullifier);
319
+ const [exists, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
320
+ siloedNullifier,
321
+ );
322
+
323
+ if (this.doMerkleOperations) {
324
+ this.trace.traceNullifierCheck(
325
+ siloedNullifier,
326
+ exists,
327
+ leafOrLowLeafPreimage,
328
+ leafOrLowLeafIndex,
329
+ leafOrLowLeafPath,
330
+ );
331
+ } else {
332
+ this.trace.traceNullifierCheck(siloedNullifier, exists);
333
+ }
334
+ return Promise.resolve(exists);
335
+ }
336
+
337
+ /**
338
+ * Helper to get membership information for a siloed nullifier when checking its existence.
339
+ * Optionally trace the nullifier check.
340
+ *
341
+ * @param siloedNullifier - the siloed nullifier to get membership information for
342
+ * @returns
343
+ * - exists - whether the nullifier exists in the nullifier set
344
+ * - leafOrLowLeafPreimage - the preimage of the nullifier leaf or its low-leaf if it doesn't exist
345
+ * - leafOrLowLeafIndex - the leaf index of the nullifier leaf or its low-leaf if it doesn't exist
346
+ * - leafOrLowLeafPath - the sibling path of the nullifier leaf or its low-leaf if it doesn't exist
347
+ */
348
+ private async getNullifierMembership(
349
+ siloedNullifier: Fr,
350
+ ): Promise<
351
+ [
352
+ /*exists=*/ boolean,
353
+ /*leafOrLowLeafPreimage=*/ NullifierLeafPreimage,
354
+ /*leafOrLowLeafIndex=*/ Fr,
355
+ /*leafOrLowLeafIndexPath=*/ Fr[],
356
+ ]
357
+ > {
302
358
  const [exists, isPending, _] = await this.nullifiers.checkExists(siloedNullifier);
303
- this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}, pending=${isPending})`);
359
+ this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), pending=${isPending}`);
304
360
 
305
361
  if (this.doMerkleOperations) {
306
362
  // Get leaf if present, low leaf if absent
@@ -308,29 +364,30 @@ export class AvmPersistableStateManager {
308
364
  const {
309
365
  preimage,
310
366
  index: leafIndex,
311
- update,
367
+ alreadyPresent,
312
368
  } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.NULLIFIER_TREE, siloedNullifier);
313
369
  const leafPreimage = preimage as NullifierLeafPreimage;
314
370
  const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
315
371
 
316
- assert(update == exists, 'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!');
372
+ assert(
373
+ alreadyPresent == exists,
374
+ 'WorldStateDB contains nullifier leaf, but merkle tree does not (or vice versa).... This is a bug!',
375
+ );
317
376
 
318
377
  if (exists) {
319
378
  this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`);
320
379
  } else {
321
380
  // Sanity check that the leaf value is skipped by low leaf when it doesn't exist
322
381
  assert(
323
- siloedNullifier.toBigInt() > leafPreimage.nullifier.toBigInt() &&
324
- siloedNullifier.toBigInt() < leafPreimage.nextNullifier.toBigInt(),
382
+ leafPreimage.nullifier.toBigInt() < siloedNullifier.toBigInt() &&
383
+ (leafPreimage.nextIndex === 0n || leafPreimage.nextNullifier.toBigInt() > siloedNullifier.toBigInt()),
325
384
  'Nullifier tree low leaf should skip the target leaf nullifier when the target leaf does not exist.',
326
385
  );
327
386
  }
328
-
329
- this.trace.traceNullifierCheck(siloedNullifier, exists, leafPreimage, new Fr(leafIndex), leafPath);
387
+ return [exists, leafPreimage, new Fr(leafIndex), leafPath];
330
388
  } else {
331
- this.trace.traceNullifierCheck(siloedNullifier, exists);
389
+ return [exists, NullifierLeafPreimage.empty(), Fr.ZERO, []];
332
390
  }
333
- return Promise.resolve(exists);
334
391
  }
335
392
 
336
393
  /**
@@ -355,11 +412,11 @@ export class AvmPersistableStateManager {
355
412
  // Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert
356
413
  // It might be better to catch the error from the insert operation
357
414
  // Trace all nullifier creations, even duplicate insertions that fail
358
- const { preimage, index, update } = await this.merkleTrees.getLeafOrLowLeafInfo(
415
+ const { preimage, index, alreadyPresent } = await this.merkleTrees.getLeafOrLowLeafInfo(
359
416
  MerkleTreeId.NULLIFIER_TREE,
360
417
  siloedNullifier,
361
418
  );
362
- if (update) {
419
+ if (alreadyPresent) {
363
420
  this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`);
364
421
  // If the nullifier is already present, we should not insert it again
365
422
  // instead we provide the direct membership path
@@ -367,7 +424,7 @@ export class AvmPersistableStateManager {
367
424
  // This just becomes a nullifier read hint
368
425
  this.trace.traceNullifierCheck(
369
426
  siloedNullifier,
370
- /*exists=*/ update,
427
+ /*exists=*/ alreadyPresent,
371
428
  preimage as NullifierLeafPreimage,
372
429
  new Fr(index),
373
430
  path,
@@ -379,6 +436,11 @@ export class AvmPersistableStateManager {
379
436
  // Cache pending nullifiers for later access
380
437
  await this.nullifiers.append(siloedNullifier);
381
438
  // We append the new nullifier
439
+ this.log.debug(
440
+ `Nullifier tree root before insertion ${this.merkleTrees.treeMap
441
+ .get(MerkleTreeId.NULLIFIER_TREE)!
442
+ .getRoot()}`,
443
+ );
382
444
  const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier);
383
445
  this.log.debug(
384
446
  `Nullifier tree root after insertion ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
@@ -472,18 +534,59 @@ export class AvmPersistableStateManager {
472
534
  const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
473
535
  const exists = instanceWithAddress !== undefined;
474
536
 
475
- // TODO: nullifier check!
537
+ let [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = [
538
+ exists,
539
+ NullifierLeafPreimage.empty(),
540
+ Fr.ZERO,
541
+ new Array<Fr>(),
542
+ ];
543
+ if (!contractAddressIsCanonical(contractAddress)) {
544
+ const contractAddressNullifier = siloNullifier(
545
+ AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
546
+ contractAddress.toField(),
547
+ );
548
+ [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
549
+ /*siloedNullifier=*/ contractAddressNullifier,
550
+ );
551
+ assert(
552
+ exists == existsInTree,
553
+ 'WorldStateDB contains contract instance, but nullifier tree does not contain contract address (or vice versa).... This is a bug!',
554
+ );
555
+ }
556
+
476
557
  if (exists) {
477
558
  const instance = new SerializableContractInstance(instanceWithAddress);
478
559
  this.log.debug(
479
560
  `Got contract instance (address=${contractAddress}): exists=${exists}, instance=${jsonStringify(instance)}`,
480
561
  );
481
- this.trace.traceGetContractInstance(contractAddress, exists, instance);
562
+ if (this.doMerkleOperations) {
563
+ this.trace.traceGetContractInstance(
564
+ contractAddress,
565
+ exists,
566
+ instance,
567
+ leafOrLowLeafPreimage,
568
+ leafOrLowLeafIndex,
569
+ leafOrLowLeafPath,
570
+ );
571
+ } else {
572
+ this.trace.traceGetContractInstance(contractAddress, exists, instance);
573
+ }
482
574
 
483
575
  return Promise.resolve(instance);
484
576
  } else {
485
577
  this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
486
- this.trace.traceGetContractInstance(contractAddress, exists);
578
+ if (this.doMerkleOperations) {
579
+ this.trace.traceGetContractInstance(
580
+ contractAddress,
581
+ exists,
582
+ /*instance=*/ undefined,
583
+ leafOrLowLeafPreimage,
584
+ leafOrLowLeafIndex,
585
+ leafOrLowLeafPath,
586
+ );
587
+ } else {
588
+ this.trace.traceGetContractInstance(contractAddress, exists);
589
+ }
487
590
  return Promise.resolve(undefined);
488
591
  }
489
592
  }
@@ -496,6 +599,26 @@ export class AvmPersistableStateManager {
496
599
  const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
497
600
  const exists = instanceWithAddress !== undefined;
498
601
 
602
+ let [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = [
603
+ exists,
604
+ NullifierLeafPreimage.empty(),
605
+ Fr.ZERO,
606
+ new Array<Fr>(),
607
+ ];
608
+ if (!contractAddressIsCanonical(contractAddress)) {
609
+ const contractAddressNullifier = siloNullifier(
610
+ AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
611
+ contractAddress.toField(),
612
+ );
613
+ [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
614
+ /*siloedNullifier=*/ contractAddressNullifier,
615
+ );
616
+ assert(
617
+ exists == existsInTree,
618
+ 'WorldStateDB contains contract instance, but nullifier tree does not contain contract address (or vice versa).... This is a bug!',
619
+ );
620
+ }
621
+
499
622
  if (exists) {
500
623
  const instance = new SerializableContractInstance(instanceWithAddress);
501
624
  const contractClass = await this.worldStateDB.getContractClass(instance.contractClassId);
@@ -517,51 +640,66 @@ export class AvmPersistableStateManager {
517
640
  publicBytecodeCommitment: bytecodeCommitment,
518
641
  };
519
642
 
520
- this.trace.traceGetBytecode(
521
- contractAddress,
522
- exists,
523
- contractClass.packedBytecode,
524
- instance,
525
- contractClassPreimage,
526
- );
643
+ if (this.doMerkleOperations) {
644
+ this.trace.traceGetBytecode(
645
+ contractAddress,
646
+ exists,
647
+ contractClass.packedBytecode,
648
+ instance,
649
+ contractClassPreimage,
650
+ leafOrLowLeafPreimage,
651
+ leafOrLowLeafIndex,
652
+ leafOrLowLeafPath,
653
+ );
654
+ } else {
655
+ this.trace.traceGetBytecode(
656
+ contractAddress,
657
+ exists,
658
+ contractClass.packedBytecode,
659
+ instance,
660
+ contractClassPreimage,
661
+ );
662
+ }
527
663
 
528
664
  return contractClass.packedBytecode;
529
665
  } else {
530
666
  // If the contract instance is not found, we assume it has not been deployed.
531
667
  // It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
532
668
  // This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
533
- this.trace.traceGetBytecode(contractAddress, exists); // bytecode, instance, class undefined
669
+ if (this.doMerkleOperations) {
670
+ this.trace.traceGetBytecode(
671
+ contractAddress,
672
+ exists,
673
+ /*instance=*/ undefined,
674
+ /*contractClass=*/ undefined,
675
+ /*bytecode=*/ undefined,
676
+ leafOrLowLeafPreimage,
677
+ leafOrLowLeafIndex,
678
+ leafOrLowLeafPath,
679
+ );
680
+ } else {
681
+ this.trace.traceGetBytecode(contractAddress, exists); // bytecode, instance, class undefined
682
+ }
534
683
  return undefined;
535
684
  }
536
685
  }
537
686
 
538
- public async traceNestedCall(
539
- forkedState: AvmPersistableStateManager,
540
- nestedEnvironment: AvmExecutionEnvironment,
541
- startGasLeft: Gas,
542
- bytecode: Buffer,
543
- avmCallResults: AvmContractCallResult,
544
- ) {
545
- const functionName = await getPublicFunctionDebugName(
546
- this.worldStateDB,
547
- nestedEnvironment.address,
548
- nestedEnvironment.functionSelector,
549
- nestedEnvironment.calldata,
550
- );
551
-
552
- this.log.verbose(`[AVM] Tracing nested external contract call ${functionName}`);
553
-
554
- this.trace.traceNestedCall(
555
- forkedState.trace,
556
- nestedEnvironment,
557
- startGasLeft,
558
- bytecode,
559
- avmCallResults,
560
- functionName,
561
- );
562
- }
563
-
564
687
  public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
565
688
  this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
566
689
  }
690
+
691
+ public async getPublicFunctionDebugName(avmEnvironment: AvmExecutionEnvironment): Promise<string> {
692
+ return await getPublicFunctionDebugName(this.worldStateDB, avmEnvironment.address, avmEnvironment.calldata);
693
+ }
694
+ }
695
+
696
+ function contractAddressIsCanonical(contractAddress: AztecAddress): boolean {
697
+ return (
698
+ contractAddress.equals(AztecAddress.fromNumber(CANONICAL_AUTH_REGISTRY_ADDRESS)) ||
699
+ contractAddress.equals(AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS)) ||
700
+ contractAddress.equals(AztecAddress.fromNumber(REGISTERER_CONTRACT_ADDRESS)) ||
701
+ contractAddress.equals(AztecAddress.fromNumber(MULTI_CALL_ENTRYPOINT_ADDRESS)) ||
702
+ contractAddress.equals(AztecAddress.fromNumber(FEE_JUICE_ADDRESS)) ||
703
+ contractAddress.equals(AztecAddress.fromNumber(ROUTER_ADDRESS))
704
+ );
567
705
  }
@@ -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,5 +1,3 @@
1
- import { Fr, FunctionSelector, Gas, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js';
2
-
3
1
  import type { AvmContext } from '../avm_context.js';
4
2
  import { type AvmContractCallResult } from '../avm_contract_call_result.js';
5
3
  import { type Field, TypeTag, Uint1 } from '../avm_memory_types.js';
@@ -45,7 +43,6 @@ abstract class ExternalCall extends Instruction {
45
43
 
46
44
  const callAddress = memory.getAs<Field>(addrOffset);
47
45
  const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
48
- const functionSelector = new Fr(PUBLIC_DISPATCH_SELECTOR);
49
46
  // If we are already in a static call, we propagate the environment.
50
47
  const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type;
51
48
 
@@ -62,15 +59,10 @@ abstract class ExternalCall extends Instruction {
62
59
  const allocatedGas = { l2Gas: allocatedL2Gas, daGas: allocatedDaGas };
63
60
  context.machineState.consumeGas(allocatedGas);
64
61
 
65
- const nestedContext = context.createNestedContractCallContext(
66
- callAddress.toAztecAddress(),
67
- calldata,
68
- allocatedGas,
69
- callType,
70
- FunctionSelector.fromField(functionSelector),
71
- );
62
+ const aztecAddress = callAddress.toAztecAddress();
63
+ const nestedContext = context.createNestedContractCallContext(aztecAddress, calldata, allocatedGas, callType);
72
64
 
73
- const simulator = new AvmSimulator(nestedContext);
65
+ const simulator = await AvmSimulator.build(nestedContext);
74
66
  const nestedCallResults: AvmContractCallResult = await simulator.execute();
75
67
  const success = !nestedCallResults.reverted;
76
68
 
@@ -102,14 +94,6 @@ abstract class ExternalCall extends Instruction {
102
94
  } else {
103
95
  context.persistableState.reject(nestedContext.persistableState);
104
96
  }
105
- await context.persistableState.traceNestedCall(
106
- /*nestedState=*/ nestedContext.persistableState,
107
- /*nestedEnvironment=*/ nestedContext.environment,
108
- /*startGasLeft=*/ Gas.from(allocatedGas),
109
- /*bytecode=*/ simulator.getBytecode()!,
110
- /*avmCallResults=*/ nestedCallResults,
111
- );
112
-
113
97
  memory.assert({ reads: calldataSize + 4, writes: 1, addressing });
114
98
  }
115
99
 
@@ -1,4 +1,4 @@
1
- import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log';
1
+ import { applyStringFormatting, createLogger } from '@aztec/foundation/log';
2
2
 
3
3
  import { type AvmContext } from '../avm_context.js';
4
4
  import { TypeTag } from '../avm_memory_types.js';
@@ -9,7 +9,7 @@ import { Instruction } from './instruction.js';
9
9
  export class DebugLog extends Instruction {
10
10
  static type: string = 'DEBUGLOG';
11
11
  static readonly opcode: Opcode = Opcode.DEBUGLOG;
12
- static readonly logger = createDebugLogger('aztec:avm_simulator:debug_log');
12
+ static readonly logger = createLogger('simulator:avm:debug_log');
13
13
 
14
14
  // Informs (de)serialization. See Instruction.deserialize.
15
15
  static readonly wireFormat: OperandType[] = [