@aztec/simulator 0.85.0 → 0.86.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 (133) hide show
  1. package/dest/private/providers/acvm_native.d.ts +1 -1
  2. package/dest/private/providers/acvm_native.d.ts.map +1 -1
  3. package/dest/private/providers/acvm_native.js +4 -3
  4. package/dest/private/providers/acvm_wasm.d.ts +2 -1
  5. package/dest/private/providers/acvm_wasm.d.ts.map +1 -1
  6. package/dest/private/providers/acvm_wasm.js +6 -1
  7. package/dest/private/providers/acvm_wasm_with_blobs.d.ts +2 -1
  8. package/dest/private/providers/acvm_wasm_with_blobs.d.ts.map +1 -1
  9. package/dest/private/providers/acvm_wasm_with_blobs.js +6 -1
  10. package/dest/private/providers/circuit_recording/simulation_provider_recorder_wrapper.d.ts +2 -1
  11. package/dest/private/providers/circuit_recording/simulation_provider_recorder_wrapper.d.ts.map +1 -1
  12. package/dest/private/providers/simulation_provider.d.ts +2 -1
  13. package/dest/private/providers/simulation_provider.d.ts.map +1 -1
  14. package/dest/public/avm/avm_context.d.ts +2 -2
  15. package/dest/public/avm/avm_context.d.ts.map +1 -1
  16. package/dest/public/avm/avm_simulator.d.ts +2 -1
  17. package/dest/public/avm/avm_simulator.d.ts.map +1 -1
  18. package/dest/public/avm/avm_simulator.js +2 -1
  19. package/dest/public/avm/avm_simulator_interface.d.ts +11 -0
  20. package/dest/public/avm/avm_simulator_interface.d.ts.map +1 -0
  21. package/dest/public/avm/avm_simulator_interface.js +3 -0
  22. package/dest/public/avm/errors.d.ts +1 -16
  23. package/dest/public/avm/errors.d.ts.map +1 -1
  24. package/dest/public/avm/errors.js +0 -37
  25. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts +1 -1
  26. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
  27. package/dest/public/avm/fixtures/avm_simulation_tester.js +1 -1
  28. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +1 -1
  29. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
  30. package/dest/public/avm/fixtures/index.d.ts +2 -85
  31. package/dest/public/avm/fixtures/index.d.ts.map +1 -1
  32. package/dest/public/avm/fixtures/index.js +2 -174
  33. package/dest/public/avm/fixtures/initializers.d.ts +42 -0
  34. package/dest/public/avm/fixtures/initializers.d.ts.map +1 -0
  35. package/dest/public/avm/fixtures/initializers.js +42 -0
  36. package/dest/public/avm/fixtures/utils.d.ts +46 -0
  37. package/dest/public/avm/fixtures/utils.d.ts.map +1 -0
  38. package/dest/public/avm/fixtures/utils.js +136 -0
  39. package/dest/public/avm/index.d.ts +0 -1
  40. package/dest/public/avm/index.d.ts.map +1 -1
  41. package/dest/public/avm/index.js +0 -1
  42. package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
  43. package/dest/public/avm/opcodes/accrued_substate.js +1 -1
  44. package/dest/public/avm/opcodes/external_calls.d.ts +3 -2
  45. package/dest/public/avm/opcodes/external_calls.d.ts.map +1 -1
  46. package/dest/public/avm/opcodes/external_calls.js +14 -9
  47. package/dest/public/avm/opcodes/instruction.d.ts +5 -5
  48. package/dest/public/avm/opcodes/instruction.d.ts.map +1 -1
  49. package/dest/public/avm/opcodes/instruction.js +6 -6
  50. package/dest/public/avm/revert_reason.d.ts +18 -0
  51. package/dest/public/avm/revert_reason.d.ts.map +1 -0
  52. package/dest/public/avm/revert_reason.js +38 -0
  53. package/dest/public/avm/serialization/bytecode_serialization.d.ts +2 -4
  54. package/dest/public/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  55. package/dest/public/avm/serialization/bytecode_serialization.js +70 -69
  56. package/dest/{common → public}/debug_fn_name.d.ts +1 -1
  57. package/dest/{common → public}/debug_fn_name.d.ts.map +1 -1
  58. package/dest/public/fixtures/index.d.ts +1 -0
  59. package/dest/public/fixtures/index.d.ts.map +1 -1
  60. package/dest/public/fixtures/index.js +1 -0
  61. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +1 -1
  62. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  63. package/dest/public/fixtures/public_tx_simulation_tester.js +3 -4
  64. package/dest/public/fixtures/simple_contract_data_source.d.ts.map +1 -0
  65. package/dest/public/{avm/fixtures → fixtures}/simple_contract_data_source.js +1 -1
  66. package/dest/public/hinting_db_sources.d.ts +15 -5
  67. package/dest/public/hinting_db_sources.d.ts.map +1 -1
  68. package/dest/public/hinting_db_sources.js +65 -27
  69. package/dest/public/index.d.ts +2 -6
  70. package/dest/public/index.d.ts.map +1 -1
  71. package/dest/public/index.js +2 -6
  72. package/dest/public/public_db_sources.d.ts +19 -52
  73. package/dest/public/public_db_sources.d.ts.map +1 -1
  74. package/dest/public/public_db_sources.js +96 -107
  75. package/dest/public/public_processor/public_processor.d.ts +6 -6
  76. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  77. package/dest/public/public_processor/public_processor.js +24 -26
  78. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +3 -2
  79. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -1
  80. package/dest/public/public_tx_simulator/measured_public_tx_simulator.js +2 -2
  81. package/dest/public/public_tx_simulator/public_tx_context.d.ts +3 -4
  82. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  83. package/dest/public/public_tx_simulator/public_tx_context.js +11 -21
  84. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +5 -4
  85. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  86. package/dest/public/public_tx_simulator/public_tx_simulator.js +21 -10
  87. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts +3 -2
  88. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts.map +1 -1
  89. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.js +2 -2
  90. package/dest/public/side_effect_trace.d.ts +1 -3
  91. package/dest/public/side_effect_trace.d.ts.map +1 -1
  92. package/dest/public/side_effect_trace.js +3 -2
  93. package/dest/public/state_manager/state_manager.d.ts +6 -4
  94. package/dest/public/state_manager/state_manager.d.ts.map +1 -1
  95. package/dest/public/state_manager/state_manager.js +20 -41
  96. package/package.json +14 -16
  97. package/src/private/providers/acvm_native.ts +5 -4
  98. package/src/private/providers/acvm_wasm.ts +5 -2
  99. package/src/private/providers/acvm_wasm_with_blobs.ts +5 -3
  100. package/src/private/providers/circuit_recording/simulation_provider_recorder_wrapper.ts +3 -2
  101. package/src/private/providers/simulation_provider.ts +2 -1
  102. package/src/public/avm/avm_context.ts +2 -2
  103. package/src/public/avm/avm_simulator.ts +4 -8
  104. package/src/public/avm/avm_simulator_interface.ts +8 -0
  105. package/src/public/avm/errors.ts +1 -53
  106. package/src/public/avm/fixtures/avm_simulation_tester.ts +1 -1
  107. package/src/public/avm/fixtures/base_avm_simulation_tester.ts +1 -1
  108. package/src/public/avm/fixtures/index.ts +2 -308
  109. package/src/public/avm/fixtures/initializers.ts +101 -0
  110. package/src/public/avm/fixtures/utils.ts +213 -0
  111. package/src/public/avm/index.ts +0 -1
  112. package/src/public/avm/opcodes/accrued_substate.ts +1 -5
  113. package/src/public/avm/opcodes/external_calls.ts +17 -11
  114. package/src/public/avm/opcodes/instruction.ts +9 -8
  115. package/src/public/avm/revert_reason.ts +55 -0
  116. package/src/public/avm/serialization/bytecode_serialization.ts +72 -74
  117. package/src/{common → public}/debug_fn_name.ts +1 -1
  118. package/src/public/fixtures/index.ts +1 -0
  119. package/src/public/fixtures/public_tx_simulation_tester.ts +3 -5
  120. package/src/public/{avm/fixtures → fixtures}/simple_contract_data_source.ts +1 -1
  121. package/src/public/hinting_db_sources.ts +104 -39
  122. package/src/public/index.ts +2 -6
  123. package/src/public/public_db_sources.ts +111 -164
  124. package/src/public/public_processor/public_processor.ts +27 -29
  125. package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +4 -3
  126. package/src/public/public_tx_simulator/public_tx_context.ts +10 -47
  127. package/src/public/public_tx_simulator/public_tx_simulator.ts +25 -10
  128. package/src/public/public_tx_simulator/telemetry_public_tx_simulator.ts +4 -3
  129. package/src/public/side_effect_trace.ts +2 -4
  130. package/src/public/state_manager/state_manager.ts +24 -50
  131. package/dest/public/avm/fixtures/simple_contract_data_source.d.ts.map +0 -1
  132. /package/dest/{common → public}/debug_fn_name.js +0 -0
  133. /package/dest/public/{avm/fixtures → fixtures}/simple_contract_data_source.d.ts +0 -0
@@ -2,7 +2,6 @@ import { NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT } from '@aztec/con
2
2
  import { Fr } from '@aztec/foundation/fields';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { Timer } from '@aztec/foundation/timer';
5
- import type { IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
6
5
  import { ContractClassRegisteredEvent } from '@aztec/protocol-contracts/class-registerer';
7
6
  import { ContractInstanceDeployedEvent } from '@aztec/protocol-contracts/instance-deployer';
8
7
  import type { FunctionSelector } from '@aztec/stdlib/abi';
@@ -15,18 +14,17 @@ import {
15
14
  computePublicBytecodeCommitment,
16
15
  } from '@aztec/stdlib/contract';
17
16
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
18
- import type {
19
- BatchInsertionResult,
20
- IndexedTreeId,
21
- MerkleTreeLeafType,
22
- MerkleTreeWriteOperations,
23
- SequentialInsertionResult,
24
- TreeInfo,
25
- } from '@aztec/stdlib/interfaces/server';
17
+ import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
26
18
  import { ContractClassLog, PrivateLog } from '@aztec/stdlib/logs';
27
19
  import type { PublicDBAccessStats } from '@aztec/stdlib/stats';
28
- import { MerkleTreeId, NullifierLeaf, PublicDataTreeLeaf, type PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
29
- import type { BlockHeader, StateReference, Tx } from '@aztec/stdlib/tx';
20
+ import {
21
+ MerkleTreeId,
22
+ NullifierLeaf,
23
+ PublicDataTreeLeaf,
24
+ type PublicDataTreeLeafPreimage,
25
+ getTreeName,
26
+ } from '@aztec/stdlib/trees';
27
+ import { TreeSnapshots, type Tx } from '@aztec/stdlib/tx';
30
28
 
31
29
  import type { PublicContractsDBInterface, PublicStateDBInterface } from './db_interfaces.js';
32
30
  import { TxContractCache } from './tx_contract_cache.js';
@@ -276,172 +274,69 @@ export class PublicContractsDB implements PublicContractsDBInterface {
276
274
  }
277
275
 
278
276
  /**
279
- * Proxy class that forwards all merkle tree operations to the underlying object.
277
+ * A high-level class that provides access to the merkle trees.
280
278
  *
281
- * NOTE: It might be possible to prune this to just the methods used in public.
282
- * Then we'd need to define a new interface, instead of MerkleTreeWriteOperations,
283
- * to be used by all our classes (that could be PublicStateDBInterface).
284
- */
285
- class ForwardMerkleTree implements MerkleTreeWriteOperations {
286
- constructor(private readonly operations: MerkleTreeWriteOperations) {}
287
-
288
- getTreeInfo(treeId: MerkleTreeId): Promise<TreeInfo> {
289
- return this.operations.getTreeInfo(treeId);
290
- }
291
-
292
- getStateReference(): Promise<StateReference> {
293
- return this.operations.getStateReference();
294
- }
295
-
296
- getInitialHeader(): BlockHeader {
297
- return this.operations.getInitialHeader();
298
- }
299
-
300
- getSiblingPath<N extends number>(treeId: MerkleTreeId, index: bigint): Promise<SiblingPath<N>> {
301
- return this.operations.getSiblingPath(treeId, index);
302
- }
303
-
304
- getPreviousValueIndex<ID extends IndexedTreeId>(
305
- treeId: ID,
306
- value: bigint,
307
- ): Promise<
308
- | {
309
- index: bigint;
310
- alreadyPresent: boolean;
311
- }
312
- | undefined
313
- > {
314
- return this.operations.getPreviousValueIndex(treeId, value);
315
- }
316
-
317
- getLeafPreimage<ID extends IndexedTreeId>(treeId: ID, index: bigint): Promise<IndexedTreeLeafPreimage | undefined> {
318
- return this.operations.getLeafPreimage(treeId, index);
319
- }
320
-
321
- findLeafIndices<ID extends MerkleTreeId>(
322
- treeId: ID,
323
- values: MerkleTreeLeafType<ID>[],
324
- ): Promise<(bigint | undefined)[]> {
325
- return this.operations.findLeafIndices(treeId, values);
326
- }
327
-
328
- findLeafIndicesAfter<ID extends MerkleTreeId>(
329
- treeId: ID,
330
- values: MerkleTreeLeafType<ID>[],
331
- startIndex: bigint,
332
- ): Promise<(bigint | undefined)[]> {
333
- return this.operations.findLeafIndicesAfter(treeId, values, startIndex);
334
- }
335
-
336
- getLeafValue<ID extends MerkleTreeId>(
337
- treeId: ID,
338
- index: bigint,
339
- ): Promise<MerkleTreeLeafType<typeof treeId> | undefined> {
340
- return this.operations.getLeafValue(treeId, index);
341
- }
342
-
343
- getBlockNumbersForLeafIndices<ID extends MerkleTreeId>(
344
- treeId: ID,
345
- leafIndices: bigint[],
346
- ): Promise<(bigint | undefined)[]> {
347
- return this.operations.getBlockNumbersForLeafIndices(treeId, leafIndices);
348
- }
349
-
350
- createCheckpoint(): Promise<void> {
351
- return this.operations.createCheckpoint();
352
- }
353
-
354
- commitCheckpoint(): Promise<void> {
355
- return this.operations.commitCheckpoint();
356
- }
357
-
358
- revertCheckpoint(): Promise<void> {
359
- return this.operations.revertCheckpoint();
360
- }
361
-
362
- appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
363
- return this.operations.appendLeaves(treeId, leaves);
364
- }
365
-
366
- updateArchive(header: BlockHeader): Promise<void> {
367
- return this.operations.updateArchive(header);
368
- }
369
-
370
- batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number, ID extends IndexedTreeId>(
371
- treeId: ID,
372
- leaves: Buffer[],
373
- subtreeHeight: number,
374
- ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
375
- return this.operations.batchInsert(treeId, leaves, subtreeHeight);
376
- }
377
-
378
- sequentialInsert<TreeHeight extends number, ID extends IndexedTreeId>(
379
- treeId: ID,
380
- leaves: Buffer[],
381
- ): Promise<SequentialInsertionResult<TreeHeight>> {
382
- return this.operations.sequentialInsert(treeId, leaves);
383
- }
384
-
385
- close(): Promise<void> {
386
- return this.operations.close();
387
- }
388
- }
389
-
390
- /**
391
- * A class that provides access to the merkle trees, and other helper methods.
279
+ * This class is just a helper wrapper around a merkle db. Anything that you can do with it
280
+ * can also be done directly with the merkle db. This class should NOT be exposed or used
281
+ * outside of `simulator/src/public`.
282
+ *
283
+ * NOTE: This class is currently written in such a way that it would generate the
284
+ * necessary hints if used with a hinting merkle db. This is a bit of a leak of concepts.
285
+ * Eventually we can have everything depend on a config/factory at the TxSimulator level
286
+ * to decide whether to use hints or not (same with tracing, etc).
392
287
  */
393
- export class PublicTreesDB extends ForwardMerkleTree implements PublicStateDBInterface {
288
+ export class PublicTreesDB implements PublicStateDBInterface {
394
289
  private logger = createLogger('simulator:public-trees-db');
395
290
 
396
- constructor(db: MerkleTreeWriteOperations) {
397
- super(db);
398
- }
291
+ constructor(private readonly db: MerkleTreeWriteOperations) {}
399
292
 
400
- /**
401
- * Reads a value from public storage, returning zero if none.
402
- * @param contract - Owner of the storage.
403
- * @param slot - Slot to read in the contract storage.
404
- * @returns The current value in the storage slot.
405
- */
406
293
  public async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
294
+ const timer = new Timer();
407
295
  const leafSlot = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
408
296
 
409
- const lowLeafResult = await this.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
297
+ const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
410
298
  if (!lowLeafResult) {
411
299
  throw new Error('Low leaf not found');
412
300
  }
413
301
 
414
- // TODO(fcarreiro): We need this for the hints. Might move it to the hinting layer.
415
- await this.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
302
+ // TODO: We need this for the hints. See class comment for more details.
303
+ await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
416
304
  // Unconditionally fetching the preimage for the hints. Move it to the hinting layer?
417
- const preimage = (await this.getLeafPreimage(
305
+ const preimage = (await this.db.getLeafPreimage(
418
306
  MerkleTreeId.PUBLIC_DATA_TREE,
419
307
  lowLeafResult.index,
420
308
  )) as PublicDataTreeLeafPreimage;
421
309
 
422
- return lowLeafResult.alreadyPresent ? preimage.leaf.value : Fr.ZERO;
310
+ const result = lowLeafResult.alreadyPresent ? preimage.leaf.value : Fr.ZERO;
311
+ this.logger.debug(`Storage read (contract=${contract}, slot=${slot}, value=${result})`, {
312
+ eventName: 'public-db-access',
313
+ duration: timer.ms(),
314
+ operation: 'storage-read',
315
+ } satisfies PublicDBAccessStats);
316
+
317
+ return result;
423
318
  }
424
319
 
425
- /**
426
- * Records a write to public storage.
427
- * @param contract - Owner of the storage.
428
- * @param slot - Slot to read in the contract storage.
429
- * @param newValue - The new value to store.
430
- * @returns The slot of the written leaf in the public data tree.
431
- */
432
320
  public async storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<void> {
321
+ const timer = new Timer();
433
322
  const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
434
323
  const publicDataWrite = new PublicDataWrite(leafSlot, newValue);
435
- await this.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, [publicDataWrite.toBuffer()]);
324
+ await this.db.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, [publicDataWrite.toBuffer()]);
325
+
326
+ this.logger.debug(`Storage write (contract=${contract}, slot=${slot}, value=${newValue})`, {
327
+ eventName: 'public-db-access',
328
+ duration: timer.ms(),
329
+ operation: 'storage-write',
330
+ } satisfies PublicDBAccessStats);
436
331
  }
437
332
 
438
333
  public async getL1ToL2LeafValue(leafIndex: bigint): Promise<Fr | undefined> {
439
334
  const timer = new Timer();
440
- const leafValue = await this.getLeafValue(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
441
- // TODO(fcarreiro): We need this for the hints. Might move it to the hinting layer.
442
- await this.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
335
+ const leafValue = await this.db.getLeafValue(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
336
+ // TODO: We need this for the hints. See class comment for more details.
337
+ await this.db.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
443
338
 
444
- this.logger.debug(`[DB] Fetched L1 to L2 message leaf value`, {
339
+ this.logger.debug(`Fetched L1 to L2 message leaf value (leafIndex=${leafIndex}, value=${leafValue})`, {
445
340
  eventName: 'public-db-access',
446
341
  duration: timer.ms(),
447
342
  operation: 'get-l1-to-l2-message-leaf-value',
@@ -451,11 +346,11 @@ export class PublicTreesDB extends ForwardMerkleTree implements PublicStateDBInt
451
346
 
452
347
  public async getNoteHash(leafIndex: bigint): Promise<Fr | undefined> {
453
348
  const timer = new Timer();
454
- const leafValue = await this.getLeafValue(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
455
- // TODO(fcarreiro): We need this for the hints. Might move it to the hinting layer.
456
- await this.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
349
+ const leafValue = await this.db.getLeafValue(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
350
+ // TODO: We need this for the hints. See class comment for more details.
351
+ await this.db.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
457
352
 
458
- this.logger.debug(`[DB] Fetched note hash leaf value`, {
353
+ this.logger.debug(`Fetched note hash leaf value (leafIndex=${leafIndex}, value=${leafValue})`, {
459
354
  eventName: 'public-db-access',
460
355
  duration: timer.ms(),
461
356
  operation: 'get-note-hash',
@@ -463,19 +358,30 @@ export class PublicTreesDB extends ForwardMerkleTree implements PublicStateDBInt
463
358
  return leafValue;
464
359
  }
465
360
 
361
+ public async writeNoteHash(noteHash: Fr): Promise<void> {
362
+ const timer = new Timer();
363
+ await this.db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [noteHash]);
364
+
365
+ this.logger.debug(`Wrote note hash (noteHash=${noteHash})`, {
366
+ eventName: 'public-db-access',
367
+ duration: timer.ms(),
368
+ operation: 'write-note-hash',
369
+ } satisfies PublicDBAccessStats);
370
+ }
371
+
466
372
  public async checkNullifierExists(nullifier: Fr): Promise<boolean> {
467
373
  const timer = new Timer();
468
- const lowLeafResult = await this.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
374
+ const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
469
375
  if (!lowLeafResult) {
470
376
  throw new Error('Low leaf not found');
471
377
  }
472
- // TODO(fcarreiro): We need this for the hints. Might move it to the hinting layer.
473
- await this.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
474
- // TODO(fcarreiro): We need this for the hints. Might move it to the hinting layer.
475
- await this.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
378
+ // TODO: We need this for the hints. See class comment for more details.
379
+ await this.db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
380
+ // TODO: We need this for the hints. See class comment for more details.
381
+ await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
476
382
  const exists = lowLeafResult.alreadyPresent;
477
383
 
478
- this.logger.debug(`[DB] Checked nullifier exists`, {
384
+ this.logger.debug(`Checked nullifier exists (nullifier=${nullifier}, exists=${exists})`, {
479
385
  eventName: 'public-db-access',
480
386
  duration: timer.ms(),
481
387
  operation: 'check-nullifier-exists',
@@ -483,30 +389,71 @@ export class PublicTreesDB extends ForwardMerkleTree implements PublicStateDBInt
483
389
  return exists;
484
390
  }
485
391
 
392
+ public async writeNullifier(siloedNullifier: Fr): Promise<void> {
393
+ const timer = new Timer();
394
+ await this.db.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()]);
395
+
396
+ this.logger.debug(`Wrote nullifier (nullifier=${siloedNullifier})`, {
397
+ eventName: 'public-db-access',
398
+ duration: timer.ms(),
399
+ operation: 'write-nullifier',
400
+ } satisfies PublicDBAccessStats);
401
+ }
402
+
486
403
  public async padTree(treeId: MerkleTreeId, leavesToInsert: number): Promise<void> {
404
+ const timer = new Timer();
405
+
487
406
  switch (treeId) {
488
407
  // Indexed trees.
489
408
  case MerkleTreeId.NULLIFIER_TREE:
490
- await this.batchInsert(
409
+ await this.db.batchInsert(
491
410
  treeId,
492
411
  Array(leavesToInsert).fill(NullifierLeaf.empty().toBuffer()),
493
412
  NULLIFIER_SUBTREE_HEIGHT,
494
413
  );
495
414
  break;
496
415
  case MerkleTreeId.PUBLIC_DATA_TREE:
497
- await this.batchInsert(
416
+ await this.db.batchInsert(
498
417
  treeId,
499
418
  Array(leavesToInsert).fill(PublicDataTreeLeaf.empty().toBuffer()),
500
419
  PUBLIC_DATA_SUBTREE_HEIGHT,
501
420
  );
502
421
  break;
503
- // Non-indexed trees.
422
+ // Append-only trees.
504
423
  case MerkleTreeId.L1_TO_L2_MESSAGE_TREE:
505
424
  case MerkleTreeId.NOTE_HASH_TREE:
506
- await this.appendLeaves(treeId, Array(leavesToInsert).fill(Fr.ZERO));
425
+ await this.db.appendLeaves(treeId, Array(leavesToInsert).fill(Fr.ZERO));
507
426
  break;
508
427
  default:
509
428
  throw new Error(`Padding not supported for tree ${treeId}`);
510
429
  }
430
+
431
+ this.logger.debug(`Padded tree (tree=${getTreeName(treeId)}, leavesToInsert=${leavesToInsert})`, {
432
+ eventName: 'public-db-access',
433
+ duration: timer.ms(),
434
+ operation: 'pad-tree',
435
+ } satisfies PublicDBAccessStats);
436
+ }
437
+
438
+ public async createCheckpoint(): Promise<void> {
439
+ await this.db.createCheckpoint();
440
+ }
441
+
442
+ public async commitCheckpoint(): Promise<void> {
443
+ await this.db.commitCheckpoint();
444
+ }
445
+
446
+ public async revertCheckpoint(): Promise<void> {
447
+ await this.db.revertCheckpoint();
448
+ }
449
+
450
+ public async getTreeSnapshots(): Promise<TreeSnapshots> {
451
+ const stateReference = await this.db.getStateReference();
452
+ return new TreeSnapshots(
453
+ stateReference.l1ToL2MessageTree,
454
+ stateReference.partial.noteHashTree,
455
+ stateReference.partial.nullifierTree,
456
+ stateReference.partial.publicDataTree,
457
+ );
511
458
  }
512
459
  }
@@ -44,7 +44,7 @@ export class PublicProcessorFactory {
44
44
  constructor(
45
45
  private contractDataSource: ContractDataSource,
46
46
  private dateProvider: DateProvider,
47
- private telemetryClient: TelemetryClient = getTelemetryClient(),
47
+ protected telemetryClient: TelemetryClient = getTelemetryClient(),
48
48
  ) {}
49
49
 
50
50
  /**
@@ -59,10 +59,9 @@ export class PublicProcessorFactory {
59
59
  globalVariables: GlobalVariables,
60
60
  skipFeeEnforcement: boolean,
61
61
  ): PublicProcessor {
62
- const treesDB = new PublicTreesDB(merkleTree);
63
62
  const contractsDB = new PublicContractsDB(this.contractDataSource);
64
63
  const publicTxSimulator = this.createPublicTxSimulator(
65
- treesDB,
64
+ merkleTree,
66
65
  contractsDB,
67
66
  globalVariables,
68
67
  /*doMerkleOperations=*/ true,
@@ -71,7 +70,7 @@ export class PublicProcessorFactory {
71
70
 
72
71
  return new PublicProcessor(
73
72
  globalVariables,
74
- treesDB,
73
+ merkleTree,
75
74
  contractsDB,
76
75
  publicTxSimulator,
77
76
  this.dateProvider,
@@ -80,14 +79,14 @@ export class PublicProcessorFactory {
80
79
  }
81
80
 
82
81
  protected createPublicTxSimulator(
83
- treesDB: PublicTreesDB,
82
+ merkleTree: MerkleTreeWriteOperations,
84
83
  contractsDB: PublicContractsDB,
85
84
  globalVariables: GlobalVariables,
86
85
  doMerkleOperations: boolean,
87
86
  skipFeeEnforcement: boolean,
88
87
  ): PublicTxSimulator {
89
88
  return new TelemetryPublicTxSimulator(
90
- treesDB,
89
+ merkleTree,
91
90
  contractsDB,
92
91
  globalVariables,
93
92
  doMerkleOperations,
@@ -110,9 +109,10 @@ class PublicProcessorTimeoutError extends Error {
110
109
  */
111
110
  export class PublicProcessor implements Traceable {
112
111
  private metrics: PublicProcessorMetrics;
112
+
113
113
  constructor(
114
114
  protected globalVariables: GlobalVariables,
115
- protected treesDB: PublicTreesDB,
115
+ private merkleTree: MerkleTreeWriteOperations,
116
116
  protected contractsDB: PublicContractsDB,
117
117
  protected publicTxSimulator: PublicTxSimulator,
118
118
  private dateProvider: DateProvider,
@@ -221,7 +221,7 @@ export class PublicProcessor implements Traceable {
221
221
  // We checkpoint the transaction here, then within the try/catch we
222
222
  // 1. Revert the checkpoint if the tx fails or needs to be discarded for any reason
223
223
  // 2. Commit the transaction in the finally block. Note that by using the ForkCheckpoint lifecycle only the first commit/revert takes effect
224
- const checkpoint = await ForkCheckpoint.new(this.treesDB);
224
+ const checkpoint = await ForkCheckpoint.new(this.merkleTree);
225
225
 
226
226
  try {
227
227
  const [processedTx, returnValues] = await this.processTx(tx, deadline);
@@ -240,16 +240,8 @@ export class PublicProcessor implements Traceable {
240
240
  continue;
241
241
  }
242
242
 
243
- if (!tx.hasPublicCalls()) {
244
- // If there are no public calls, perform all tree insertions for side effects from private
245
- // When there are public calls, the PublicTxSimulator & AVM handle tree insertions.
246
- await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
247
- // Add any contracts registered/deployed in this private-only tx to the block-level cache
248
- // (add to tx-level cache and then commit to block-level cache)
249
- await this.contractsDB.addNewContracts(tx);
250
- this.contractsDB.commitContractsForTx();
251
- }
252
-
243
+ // FIXME(fcarreiro): it's ugly to have to notify the validator of nullifiers.
244
+ // I'd rather pass the validators the processedTx as well and let them deal with it.
253
245
  nullifierCache?.addNullifiers(processedTx.txEffect.nullifiers.map(n => n.toBuffer()));
254
246
  result.push(processedTx);
255
247
  returns = returns.concat(returnValues);
@@ -332,12 +324,12 @@ export class PublicProcessor implements Traceable {
332
324
  // b) always had a txHandler with the same db passed to it as this.db, which updated the db in buildBaseRollupHints in this loop
333
325
  // To see how this ^ happens, move back to one shared db in test_context and run orchestrator_multi_public_functions.test.ts
334
326
  // The below is taken from buildBaseRollupHints:
335
- await this.treesDB.appendLeaves(
327
+ await this.merkleTree.appendLeaves(
336
328
  MerkleTreeId.NOTE_HASH_TREE,
337
329
  padArrayEnd(processedTx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
338
330
  );
339
331
  try {
340
- await this.treesDB.batchInsert(
332
+ await this.merkleTree.batchInsert(
341
333
  MerkleTreeId.NULLIFIER_TREE,
342
334
  padArrayEnd(processedTx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()),
343
335
  NULLIFIER_SUBTREE_HEIGHT,
@@ -352,11 +344,6 @@ export class PublicProcessor implements Traceable {
352
344
  }
353
345
  }
354
346
 
355
- // The only public data write should be for fee payment
356
- await this.treesDB.sequentialInsert(
357
- MerkleTreeId.PUBLIC_DATA_TREE,
358
- processedTx.txEffect.publicDataWrites.map(x => x.toBuffer()),
359
- );
360
347
  const treeInsertionEnd = process.hrtime.bigint();
361
348
  this.metrics.recordTreeInsertions(Number(treeInsertionEnd - treeInsertionStart) / 1_000);
362
349
  }
@@ -398,14 +385,16 @@ export class PublicProcessor implements Traceable {
398
385
  * This is used in private only txs, since for txs with public calls
399
386
  * the avm handles the fee payment itself.
400
387
  */
401
- private async getFeePaymentPublicDataWrite(txFee: Fr, feePayer: AztecAddress): Promise<PublicDataWrite> {
388
+ private async performFeePaymentPublicDataWrite(txFee: Fr, feePayer: AztecAddress): Promise<PublicDataWrite> {
402
389
  const feeJuiceAddress = ProtocolContractAddress.FeeJuice;
403
390
  const balanceSlot = await computeFeePayerBalanceStorageSlot(feePayer);
404
391
  const leafSlot = await computeFeePayerBalanceLeafSlot(feePayer);
392
+ // This high-level db is used as a convenient helper. It could be done with the merkleTree directly.
393
+ const treesDB = new PublicTreesDB(this.merkleTree);
405
394
 
406
395
  this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${feePayer}`);
407
396
 
408
- const balance = await this.treesDB.storageRead(feeJuiceAddress, balanceSlot);
397
+ const balance = await treesDB.storageRead(feeJuiceAddress, balanceSlot);
409
398
 
410
399
  if (balance.lt(txFee)) {
411
400
  throw new Error(
@@ -414,7 +403,7 @@ export class PublicProcessor implements Traceable {
414
403
  }
415
404
 
416
405
  const updatedBalance = balance.sub(txFee);
417
- await this.treesDB.storageWrite(feeJuiceAddress, balanceSlot, updatedBalance);
406
+ await treesDB.storageWrite(feeJuiceAddress, balanceSlot, updatedBalance);
418
407
 
419
408
  return new PublicDataWrite(leafSlot, updatedBalance);
420
409
  }
@@ -426,7 +415,7 @@ export class PublicProcessor implements Traceable {
426
415
  const gasFees = this.globalVariables.gasFees;
427
416
  const transactionFee = tx.data.gasUsed.computeFee(gasFees);
428
417
 
429
- const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(transactionFee, tx.data.feePayer);
418
+ const feePaymentPublicDataWrite = await this.performFeePaymentPublicDataWrite(transactionFee, tx.data.feePayer);
430
419
 
431
420
  const processedTx = await makeProcessedTxFromPrivateOnlyTx(
432
421
  tx,
@@ -445,6 +434,15 @@ export class PublicProcessor implements Traceable {
445
434
  .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log))
446
435
  .map(log => ContractClassRegisteredEvent.fromLog(log)),
447
436
  );
437
+
438
+ // Fee payment insertion has already been done. Do the rest.
439
+ await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
440
+
441
+ // Add any contracts registered/deployed in this private-only tx to the block-level cache
442
+ // (add to tx-level cache and then commit to block-level cache)
443
+ await this.contractsDB.addNewContracts(tx);
444
+ this.contractsDB.commitContractsForTx();
445
+
448
446
  return [processedTx, undefined];
449
447
  }
450
448
 
@@ -2,11 +2,12 @@ import type { Fr } from '@aztec/foundation/fields';
2
2
  import { Timer } from '@aztec/foundation/timer';
3
3
  import type { Gas } from '@aztec/stdlib/gas';
4
4
  import type { AvmSimulationStats } from '@aztec/stdlib/stats';
5
+ import type { MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
5
6
  import { type GlobalVariables, PublicCallRequestWithCalldata, Tx, TxExecutionPhase } from '@aztec/stdlib/tx';
6
7
 
7
8
  import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
8
9
  import type { ExecutorMetricsInterface } from '../executor_metrics_interface.js';
9
- import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
10
+ import type { PublicContractsDB } from '../public_db_sources.js';
10
11
  import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
11
12
  import { PublicTxContext } from './public_tx_context.js';
12
13
  import { type ProcessedPhase, type PublicTxResult, PublicTxSimulator } from './public_tx_simulator.js';
@@ -16,14 +17,14 @@ import { type ProcessedPhase, type PublicTxResult, PublicTxSimulator } from './p
16
17
  */
17
18
  export class MeasuredPublicTxSimulator extends PublicTxSimulator {
18
19
  constructor(
19
- treesDB: PublicTreesDB,
20
+ merkleTree: MerkleTreeWriteOperations,
20
21
  contractsDB: PublicContractsDB,
21
22
  globalVariables: GlobalVariables,
22
23
  doMerkleOperations: boolean = false,
23
24
  skipFeeEnforcement: boolean = false,
24
25
  protected readonly metrics: ExecutorMetricsInterface,
25
26
  ) {
26
- super(treesDB, contractsDB, globalVariables, doMerkleOperations, skipFeeEnforcement);
27
+ super(merkleTree, contractsDB, globalVariables, doMerkleOperations, skipFeeEnforcement);
27
28
  }
28
29
 
29
30
  public override async simulate(tx: Tx, txLabel: string = 'unlabeledTx'): Promise<PublicTxResult> {