@aztec/simulator 0.80.0 → 0.81.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 (89) hide show
  1. package/dest/common/db_interfaces.d.ts +24 -5
  2. package/dest/common/db_interfaces.d.ts.map +1 -1
  3. package/dest/common/debug_fn_name.d.ts +2 -2
  4. package/dest/common/debug_fn_name.d.ts.map +1 -1
  5. package/dest/private/acvm/deserialize.d.ts +19 -0
  6. package/dest/private/acvm/deserialize.d.ts.map +1 -1
  7. package/dest/private/acvm/deserialize.js +29 -0
  8. package/dest/private/acvm/oracle/oracle.d.ts +2 -0
  9. package/dest/private/acvm/oracle/oracle.d.ts.map +1 -1
  10. package/dest/private/acvm/oracle/oracle.js +18 -3
  11. package/dest/private/acvm/oracle/typed_oracle.d.ts +2 -1
  12. package/dest/private/acvm/oracle/typed_oracle.d.ts.map +1 -1
  13. package/dest/private/acvm/oracle/typed_oracle.js +3 -0
  14. package/dest/private/acvm/serialize.d.ts +11 -0
  15. package/dest/private/acvm/serialize.d.ts.map +1 -1
  16. package/dest/private/acvm/serialize.js +27 -0
  17. package/dest/private/execution_data_provider.d.ts +12 -4
  18. package/dest/private/execution_data_provider.d.ts.map +1 -1
  19. package/dest/private/private_execution_oracle.d.ts.map +1 -1
  20. package/dest/private/private_execution_oracle.js +1 -1
  21. package/dest/private/unconstrained_execution_oracle.d.ts +4 -2
  22. package/dest/private/unconstrained_execution_oracle.d.ts.map +1 -1
  23. package/dest/private/unconstrained_execution_oracle.js +6 -2
  24. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
  25. package/dest/public/avm/fixtures/avm_simulation_tester.js +5 -5
  26. package/dest/public/avm/fixtures/index.d.ts +4 -4
  27. package/dest/public/avm/fixtures/index.d.ts.map +1 -1
  28. package/dest/public/avm/fixtures/index.js +9 -6
  29. package/dest/public/avm/fixtures/simple_contract_data_source.d.ts +1 -2
  30. package/dest/public/avm/fixtures/simple_contract_data_source.d.ts.map +1 -1
  31. package/dest/public/avm/fixtures/simple_contract_data_source.js +0 -3
  32. package/dest/public/avm/journal/journal.d.ts +16 -70
  33. package/dest/public/avm/journal/journal.d.ts.map +1 -1
  34. package/dest/public/avm/journal/journal.js +88 -210
  35. package/dest/public/avm/journal/nullifiers.d.ts +2 -2
  36. package/dest/public/avm/journal/nullifiers.d.ts.map +1 -1
  37. package/dest/public/avm/journal/public_storage.d.ts +2 -2
  38. package/dest/public/avm/journal/public_storage.d.ts.map +1 -1
  39. package/dest/public/avm/test_utils.d.ts +10 -13
  40. package/dest/public/avm/test_utils.d.ts.map +1 -1
  41. package/dest/public/avm/test_utils.js +7 -12
  42. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +3 -3
  43. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  44. package/dest/public/fixtures/public_tx_simulation_tester.js +10 -9
  45. package/dest/public/hinting_db_sources.d.ts +19 -0
  46. package/dest/public/hinting_db_sources.d.ts.map +1 -0
  47. package/dest/public/hinting_db_sources.js +36 -0
  48. package/dest/public/public_db_sources.d.ts +45 -21
  49. package/dest/public/public_db_sources.d.ts.map +1 -1
  50. package/dest/public/public_db_sources.js +79 -24
  51. package/dest/public/public_processor/public_processor.d.ts +5 -5
  52. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  53. package/dest/public/public_processor/public_processor.js +21 -20
  54. package/dest/public/public_tx_simulator/public_tx_context.d.ts +9 -14
  55. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  56. package/dest/public/public_tx_simulator/public_tx_context.js +15 -19
  57. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +9 -6
  58. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  59. package/dest/public/public_tx_simulator/public_tx_simulator.js +28 -14
  60. package/dest/public/side_effect_trace.d.ts +6 -22
  61. package/dest/public/side_effect_trace.d.ts.map +1 -1
  62. package/dest/public/side_effect_trace.js +11 -70
  63. package/dest/public/side_effect_trace_interface.d.ts +5 -19
  64. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  65. package/package.json +14 -14
  66. package/src/common/db_interfaces.ts +26 -5
  67. package/src/common/debug_fn_name.ts +2 -2
  68. package/src/private/acvm/deserialize.ts +33 -0
  69. package/src/private/acvm/oracle/oracle.ts +37 -3
  70. package/src/private/acvm/oracle/typed_oracle.ts +5 -1
  71. package/src/private/acvm/serialize.ts +28 -0
  72. package/src/private/execution_data_provider.ts +13 -4
  73. package/src/private/private_execution_oracle.ts +5 -1
  74. package/src/private/unconstrained_execution_oracle.ts +12 -3
  75. package/src/public/avm/fixtures/avm_simulation_tester.ts +8 -5
  76. package/src/public/avm/fixtures/index.ts +16 -10
  77. package/src/public/avm/fixtures/simple_contract_data_source.ts +1 -10
  78. package/src/public/avm/journal/journal.ts +119 -353
  79. package/src/public/avm/journal/nullifiers.ts +2 -2
  80. package/src/public/avm/journal/public_storage.ts +2 -2
  81. package/src/public/avm/test_utils.ts +20 -29
  82. package/src/public/fixtures/public_tx_simulation_tester.ts +9 -12
  83. package/src/public/hinting_db_sources.ts +71 -0
  84. package/src/public/public_db_sources.ts +131 -29
  85. package/src/public/public_processor/public_processor.ts +22 -21
  86. package/src/public/public_tx_simulator/public_tx_context.ts +30 -38
  87. package/src/public/public_tx_simulator/public_tx_simulator.ts +47 -17
  88. package/src/public/side_effect_trace.ts +8 -172
  89. package/src/public/side_effect_trace_interface.ts +4 -55
@@ -1,6 +1,6 @@
1
1
  import type { Fr } from '@aztec/foundation/fields';
2
2
 
3
- import type { WorldStateDB } from '../../public_db_sources.js';
3
+ import type { PublicTreesDB } from '../../public_db_sources.js';
4
4
 
5
5
  /**
6
6
  * A class to manage new nullifier staging and existence checks during a contract call's AVM simulation.
@@ -10,7 +10,7 @@ import type { WorldStateDB } from '../../public_db_sources.js';
10
10
  export class NullifierManager {
11
11
  constructor(
12
12
  /** Reference to node storage. Checked on parent cache-miss. */
13
- private readonly hostNullifiers: WorldStateDB,
13
+ private readonly hostNullifiers: PublicTreesDB,
14
14
  /** Cache of siloed nullifiers. */
15
15
  private cache: Set<bigint> = new Set(),
16
16
  /** Parent nullifier manager to fall back on */
@@ -1,7 +1,7 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
2
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
3
 
4
- import type { PublicStateDB } from '../../../common/db_interfaces.js';
4
+ import type { PublicStateDBInterface } from '../../../common/db_interfaces.js';
5
5
 
6
6
  type PublicStorageReadResult = {
7
7
  value: Fr;
@@ -19,7 +19,7 @@ export class PublicStorage {
19
19
 
20
20
  constructor(
21
21
  /** Reference to node storage. Checked on parent cache-miss. */
22
- private readonly hostPublicStorage: PublicStateDB,
22
+ private readonly hostPublicStorage: PublicStateDBInterface,
23
23
  /** Parent's storage. Checked on this' cache-miss. */
24
24
  private readonly parent?: PublicStorage,
25
25
  ) {
@@ -1,47 +1,34 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
- import {
3
- type ContractClassPublic,
4
- type ContractInstanceWithAddress,
5
- computePublicBytecodeCommitment,
6
- } from '@aztec/stdlib/contract';
2
+ import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
7
3
 
8
4
  import type { jest } from '@jest/globals';
9
5
  import { mock } from 'jest-mock-extended';
10
6
 
11
- import type { WorldStateDB } from '../../public/public_db_sources.js';
7
+ import type { PublicContractsDB, PublicTreesDB } from '../../public/public_db_sources.js';
12
8
  import type { PublicSideEffectTraceInterface } from '../side_effect_trace_interface.js';
13
9
 
14
- export async function mockGetBytecode(worldStateDB: WorldStateDB, bytecode: Buffer) {
15
- const commitment = await computePublicBytecodeCommitment(bytecode);
16
- (worldStateDB as jest.Mocked<WorldStateDB>).getBytecodeCommitment.mockResolvedValue(commitment);
17
- }
18
-
19
10
  export function mockTraceFork(trace: PublicSideEffectTraceInterface, nestedTrace?: PublicSideEffectTraceInterface) {
20
11
  (trace as jest.Mocked<PublicSideEffectTraceInterface>).fork.mockReturnValue(
21
12
  nestedTrace ?? mock<PublicSideEffectTraceInterface>(),
22
13
  );
23
14
  }
24
15
 
25
- export function mockStorageRead(worldStateDB: WorldStateDB, value: Fr) {
26
- (worldStateDB as jest.Mocked<WorldStateDB>).storageRead.mockResolvedValue(value);
16
+ export function mockStorageRead(worldStateDB: PublicTreesDB, value: Fr) {
17
+ (worldStateDB as jest.Mocked<PublicTreesDB>).storageRead.mockResolvedValue(value);
27
18
  }
28
19
 
29
20
  export function mockNoteHashCount(mockedTrace: PublicSideEffectTraceInterface, count: number) {
30
21
  (mockedTrace as jest.Mocked<PublicSideEffectTraceInterface>).getNoteHashCount.mockReturnValue(count);
31
22
  }
32
23
 
33
- export function mockStorageReadWithMap(worldStateDB: WorldStateDB, mockedStorage: Map<bigint, Fr>) {
34
- (worldStateDB as jest.Mocked<WorldStateDB>).storageRead.mockImplementation((_address, slot) =>
24
+ export function mockStorageReadWithMap(worldStateDB: PublicTreesDB, mockedStorage: Map<bigint, Fr>) {
25
+ (worldStateDB as jest.Mocked<PublicTreesDB>).storageRead.mockImplementation((_address, slot) =>
35
26
  Promise.resolve(mockedStorage.get(slot.toBigInt()) ?? Fr.ZERO),
36
27
  );
37
28
  }
38
29
 
39
- export function mockGetBytecodeCommitment(worldStateDB: WorldStateDB, commitment: Fr) {
40
- (worldStateDB as jest.Mocked<WorldStateDB>).getBytecodeCommitment.mockResolvedValue(commitment);
41
- }
42
-
43
- export function mockNoteHashExists(worldStateDB: WorldStateDB, _leafIndex: Fr, value?: Fr) {
44
- (worldStateDB as jest.Mocked<WorldStateDB>).getCommitmentValue.mockImplementation((index: bigint) => {
30
+ export function mockNoteHashExists(worldStateDB: PublicTreesDB, _leafIndex: Fr, value?: Fr) {
31
+ (worldStateDB as jest.Mocked<PublicTreesDB>).getCommitmentValue.mockImplementation((index: bigint) => {
45
32
  if (index == _leafIndex.toBigInt()) {
46
33
  return Promise.resolve(value);
47
34
  } else {
@@ -51,17 +38,17 @@ export function mockNoteHashExists(worldStateDB: WorldStateDB, _leafIndex: Fr, v
51
38
  });
52
39
  }
53
40
 
54
- export function mockGetNullifierIndex(worldStateDB: WorldStateDB, leafIndex: Fr, _ignoredValue?: Fr) {
55
- (worldStateDB as jest.Mocked<WorldStateDB>).getNullifierIndex.mockResolvedValue(leafIndex.toBigInt());
41
+ export function mockGetNullifierIndex(worldStateDB: PublicTreesDB, leafIndex: Fr, _ignoredValue?: Fr) {
42
+ (worldStateDB as jest.Mocked<PublicTreesDB>).getNullifierIndex.mockResolvedValue(leafIndex.toBigInt());
56
43
  }
57
44
 
58
45
  export function mockL1ToL2MessageExists(
59
- worldStateDB: WorldStateDB,
46
+ worldStateDB: PublicTreesDB,
60
47
  leafIndex: Fr,
61
48
  value: Fr,
62
49
  valueAtOtherIndices?: Fr,
63
50
  ) {
64
- (worldStateDB as jest.Mocked<WorldStateDB>).getL1ToL2LeafValue.mockImplementation((index: bigint) => {
51
+ (worldStateDB as jest.Mocked<PublicTreesDB>).getL1ToL2LeafValue.mockImplementation((index: bigint) => {
65
52
  if (index == leafIndex.toBigInt()) {
66
53
  return Promise.resolve(value);
67
54
  } else {
@@ -72,10 +59,14 @@ export function mockL1ToL2MessageExists(
72
59
  });
73
60
  }
74
61
 
75
- export function mockGetContractInstance(worldStateDB: WorldStateDB, contractInstance: ContractInstanceWithAddress) {
76
- (worldStateDB as jest.Mocked<WorldStateDB>).getContractInstance.mockResolvedValue(contractInstance);
62
+ export function mockGetContractInstance(contractsDB: PublicContractsDB, contractInstance: ContractInstanceWithAddress) {
63
+ (contractsDB as jest.Mocked<PublicContractsDB>).getContractInstance.mockResolvedValue(contractInstance);
64
+ }
65
+
66
+ export function mockGetContractClass(contractsDB: PublicContractsDB, contractClass: ContractClassPublic) {
67
+ (contractsDB as jest.Mocked<PublicContractsDB>).getContractClass.mockResolvedValue(contractClass);
77
68
  }
78
69
 
79
- export function mockGetContractClass(worldStateDB: WorldStateDB, contractClass: ContractClassPublic) {
80
- (worldStateDB as jest.Mocked<WorldStateDB>).getContractClass.mockResolvedValue(contractClass);
70
+ export function mockGetBytecodeCommitment(contractsDB: PublicContractsDB, commitment: Fr) {
71
+ (contractsDB as jest.Mocked<PublicContractsDB>).getBytecodeCommitment.mockResolvedValue(commitment);
81
72
  }
@@ -11,7 +11,7 @@ import { NativeWorldStateService } from '@aztec/world-state';
11
11
  import { BaseAvmSimulationTester } from '../avm/fixtures/base_avm_simulation_tester.js';
12
12
  import { getContractFunctionArtifact, getFunctionSelector } from '../avm/fixtures/index.js';
13
13
  import { SimpleContractDataSource } from '../avm/fixtures/simple_contract_data_source.js';
14
- import { WorldStateDB } from '../public_db_sources.js';
14
+ import { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
15
15
  import { type PublicTxResult, PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
16
16
  import { createTxForPublicCalls } from './index.js';
17
17
 
@@ -35,19 +35,14 @@ export type TestEnqueuedCall = {
35
35
  export class PublicTxSimulationTester extends BaseAvmSimulationTester {
36
36
  private txCount = 0;
37
37
 
38
- constructor(
39
- private worldStateDB: WorldStateDB,
40
- contractDataSource: SimpleContractDataSource,
41
- merkleTrees: MerkleTreeWriteOperations,
42
- ) {
43
- super(contractDataSource, merkleTrees);
38
+ constructor(private merkleTree: MerkleTreeWriteOperations, contractDataSource: SimpleContractDataSource) {
39
+ super(contractDataSource, merkleTree);
44
40
  }
45
41
 
46
42
  public static async create(): Promise<PublicTxSimulationTester> {
47
43
  const contractDataSource = new SimpleContractDataSource();
48
- const merkleTrees = await (await NativeWorldStateService.tmp()).fork();
49
- const worldStateDB = new WorldStateDB(merkleTrees, contractDataSource);
50
- return new PublicTxSimulationTester(worldStateDB, contractDataSource, merkleTrees);
44
+ const merkleTree = await (await NativeWorldStateService.tmp()).fork();
45
+ return new PublicTxSimulationTester(merkleTree, contractDataSource);
51
46
  }
52
47
 
53
48
  public async createTx(
@@ -137,7 +132,9 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
137
132
 
138
133
  await this.setFeePayerBalance(feePayer);
139
134
 
140
- const simulator = new PublicTxSimulator(this.merkleTrees, this.worldStateDB, globals, /*doMerkleOperations=*/ true);
135
+ const treesDB = new PublicTreesDB(this.merkleTree);
136
+ const contractsDB = new PublicContractsDB(this.contractDataSource);
137
+ const simulator = new PublicTxSimulator(treesDB, contractsDB, globals, /*doMerkleOperations=*/ true);
141
138
 
142
139
  const startTime = performance.now();
143
140
  const avmResult = await simulator.simulate(tx);
@@ -170,7 +167,7 @@ async function executionRequestForCall(
170
167
  return new PublicExecutionRequest(callContext, calldata);
171
168
  }
172
169
 
173
- function defaultGlobals() {
170
+ export function defaultGlobals() {
174
171
  const globals = GlobalVariables.empty();
175
172
  globals.timestamp = TIMESTAMP;
176
173
  globals.gasFees = DEFAULT_GAS_FEES; // apply some nonzero default gas fees
@@ -0,0 +1,71 @@
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { FunctionSelector } from '@aztec/stdlib/abi';
3
+ import {
4
+ AvmBytecodeCommitmentHint,
5
+ AvmContractClassHint,
6
+ AvmContractInstanceHint,
7
+ type AvmExecutionHints,
8
+ } from '@aztec/stdlib/avm';
9
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
10
+ import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
11
+
12
+ import type { PublicContractsDBInterface } from '../server.js';
13
+
14
+ /**
15
+ * A public contracts database that forwards requests and collects AVM hints.
16
+ */
17
+ export class HintingPublicContractsDB implements PublicContractsDBInterface {
18
+ constructor(private readonly db: PublicContractsDBInterface, public readonly hints: AvmExecutionHints) {}
19
+
20
+ public async getContractInstance(
21
+ address: AztecAddress,
22
+ blockNumber: number,
23
+ ): Promise<ContractInstanceWithAddress | undefined> {
24
+ const instance = await this.db.getContractInstance(address, blockNumber);
25
+ if (instance) {
26
+ // We don't need to hint the block number because it doesn't change.
27
+ this.hints.contractInstances.push(
28
+ new AvmContractInstanceHint(
29
+ instance.address,
30
+ instance.salt,
31
+ instance.deployer,
32
+ instance.currentContractClassId,
33
+ instance.originalContractClassId,
34
+ instance.initializationHash,
35
+ instance.publicKeys,
36
+ ),
37
+ );
38
+ }
39
+ return instance;
40
+ }
41
+
42
+ public async getContractClass(contractClassId: Fr): Promise<ContractClassPublic | undefined> {
43
+ const contractClass = await this.db.getContractClass(contractClassId);
44
+ if (contractClass) {
45
+ this.hints.contractClasses.push(
46
+ new AvmContractClassHint(
47
+ contractClass.id,
48
+ contractClass.artifactHash,
49
+ contractClass.privateFunctionsRoot,
50
+ contractClass.packedBytecode,
51
+ ),
52
+ );
53
+ }
54
+ return contractClass;
55
+ }
56
+
57
+ public async getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
58
+ const commitment = await this.db.getBytecodeCommitment(contractClassId);
59
+ if (commitment) {
60
+ this.hints.bytecodeCommitments.push(new AvmBytecodeCommitmentHint(contractClassId, commitment));
61
+ }
62
+ return commitment;
63
+ }
64
+
65
+ public async getDebugFunctionName(
66
+ contractAddress: AztecAddress,
67
+ selector: FunctionSelector,
68
+ ): Promise<string | undefined> {
69
+ return await this.db.getDebugFunctionName(contractAddress, selector);
70
+ }
71
+ }
@@ -1,6 +1,7 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
  import { Timer } from '@aztec/foundation/timer';
4
+ import type { IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
4
5
  import { ContractClassRegisteredEvent } from '@aztec/protocol-contracts/class-registerer';
5
6
  import { ContractInstanceDeployedEvent } from '@aztec/protocol-contracts/instance-deployer';
6
7
  import type { FunctionSelector } from '@aztec/stdlib/abi';
@@ -14,25 +15,29 @@ import {
14
15
  } from '@aztec/stdlib/contract';
15
16
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
16
17
  import type {
17
- MerkleTreeCheckpointOperations,
18
+ BatchInsertionResult,
19
+ IndexedTreeId,
20
+ MerkleTreeLeafType,
18
21
  MerkleTreeReadOperations,
19
22
  MerkleTreeWriteOperations,
23
+ SequentialInsertionResult,
24
+ TreeInfo,
20
25
  } from '@aztec/stdlib/interfaces/server';
21
26
  import { ContractClassLog, PrivateLog } from '@aztec/stdlib/logs';
22
27
  import type { PublicDBAccessStats } from '@aztec/stdlib/stats';
23
28
  import { MerkleTreeId, type PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
24
- import type { Tx } from '@aztec/stdlib/tx';
29
+ import type { BlockHeader, StateReference, Tx } from '@aztec/stdlib/tx';
25
30
 
26
- import type { PublicContractsDB, PublicStateDB } from '../common/db_interfaces.js';
31
+ import type { PublicContractsDBInterface, PublicStateDBInterface } from '../common/db_interfaces.js';
27
32
  import { TxContractCache } from './tx_contract_cache.js';
28
33
 
29
34
  /**
30
- * Implements the PublicContractsDB using a ContractDataSource.
35
+ * Implements the PublicContractsDBInterface using a ContractDataSource.
31
36
  * Progressively records contracts in transaction as they are processed in a block.
32
37
  * Separates block-level contract information (from processed/included txs) from the
33
38
  * current tx's contract information (which may be cleared on tx revert/death).
34
39
  */
35
- export class ContractsDataSourcePublicDB implements PublicContractsDB {
40
+ export class PublicContractsDB implements PublicContractsDBInterface {
36
41
  // Two caching layers for contract classes and instances.
37
42
  // Tx-level cache:
38
43
  // - The current tx's new contract information is cached
@@ -210,13 +215,23 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
210
215
  this.currentTxRevertibleCache.clear();
211
216
  }
212
217
 
213
- public async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
218
+ // TODO(fcarreiro/alvaro): This method currently needs a blockNumber. Since this class
219
+ // is only ever used for a given block, it should be possible to construct it with the
220
+ // block number and then forget about it. However, since this class (and interface) is
221
+ // currently more externally exposed than we'd want to, Facundo preferred to not add it
222
+ // to the constructor right now. If we can make this class more private, we should
223
+ // reconsider this. A litmus test is in how many places we need to initialize with a
224
+ // dummy block number (tests or not) and pass block numbers to `super`.
225
+ public async getContractInstance(
226
+ address: AztecAddress,
227
+ blockNumber: number,
228
+ ): Promise<ContractInstanceWithAddress | undefined> {
214
229
  // Check caches in order: tx revertible -> tx non-revertible -> block -> data source
215
230
  return (
216
231
  this.currentTxRevertibleCache.getInstance(address) ??
217
232
  this.currentTxNonRevertibleCache.getInstance(address) ??
218
233
  this.blockCache.getInstance(address) ??
219
- (await this.dataSource.getContract(address))
234
+ (await this.dataSource.getContract(address, blockNumber))
220
235
  );
221
236
  }
222
237
 
@@ -261,38 +276,125 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
261
276
  }
262
277
 
263
278
  /**
264
- * A public state DB that reads and writes to the world state.
279
+ * Proxy class that forwards all merkle tree operations to the underlying object.
280
+ *
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).
265
284
  */
266
- export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicStateDB, MerkleTreeCheckpointOperations {
267
- private logger = createLogger('simulator:world-state-db');
285
+ class ForwardMerkleTree implements MerkleTreeWriteOperations {
286
+ constructor(private readonly operations: MerkleTreeWriteOperations) {}
268
287
 
269
- constructor(public db: MerkleTreeWriteOperations, dataSource: ContractDataSource) {
270
- super(dataSource);
288
+ getTreeInfo(treeId: MerkleTreeId): Promise<TreeInfo> {
289
+ return this.operations.getTreeInfo(treeId);
271
290
  }
272
291
 
273
- /**
274
- * Checkpoints the current fork state
275
- */
276
- public async createCheckpoint() {
277
- await this.db.createCheckpoint();
292
+ getStateReference(): Promise<StateReference> {
293
+ return this.operations.getStateReference();
278
294
  }
279
295
 
280
- /**
281
- * Commits the current checkpoint
282
- */
283
- public async commitCheckpoint() {
284
- await this.db.commitCheckpoint();
296
+ getInitialHeader(): BlockHeader {
297
+ return this.operations.getInitialHeader();
285
298
  }
286
299
 
287
- /**
288
- * Reverts the current checkpoint
289
- */
290
- public async revertCheckpoint() {
291
- await this.db.revertCheckpoint();
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();
292
360
  }
293
361
 
294
- public getMerkleInterface(): MerkleTreeWriteOperations {
295
- return this.db;
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.
392
+ */
393
+ export class PublicTreesDB extends ForwardMerkleTree implements PublicStateDBInterface {
394
+ private logger = createLogger('simulator:public-trees-db');
395
+
396
+ constructor(public db: MerkleTreeWriteOperations) {
397
+ super(db);
296
398
  }
297
399
 
298
400
  /**
@@ -33,7 +33,7 @@ import {
33
33
  } from '@aztec/telemetry-client';
34
34
  import { ForkCheckpoint } from '@aztec/world-state/native';
35
35
 
36
- import { WorldStateDB } from '../public_db_sources.js';
36
+ import { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
37
37
  import { PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
38
38
  import { PublicProcessorMetrics } from './public_processor_metrics.js';
39
39
 
@@ -59,10 +59,11 @@ export class PublicProcessorFactory {
59
59
  globalVariables: GlobalVariables,
60
60
  skipFeeEnforcement: boolean,
61
61
  ): PublicProcessor {
62
- const worldStateDB = new WorldStateDB(merkleTree, this.contractDataSource);
62
+ const treesDB = new PublicTreesDB(merkleTree);
63
+ const contractsDB = new PublicContractsDB(this.contractDataSource);
63
64
  const publicTxSimulator = this.createPublicTxSimulator(
64
- merkleTree,
65
- worldStateDB,
65
+ treesDB,
66
+ contractsDB,
66
67
  globalVariables,
67
68
  /*doMerkleOperations=*/ true,
68
69
  skipFeeEnforcement,
@@ -70,9 +71,9 @@ export class PublicProcessorFactory {
70
71
  );
71
72
 
72
73
  return new PublicProcessor(
73
- merkleTree,
74
74
  globalVariables,
75
- worldStateDB,
75
+ treesDB,
76
+ contractsDB,
76
77
  publicTxSimulator,
77
78
  this.dateProvider,
78
79
  this.telemetryClient,
@@ -80,16 +81,16 @@ export class PublicProcessorFactory {
80
81
  }
81
82
 
82
83
  protected createPublicTxSimulator(
83
- db: MerkleTreeWriteOperations,
84
- worldStateDB: WorldStateDB,
84
+ treesDB: PublicTreesDB,
85
+ contractsDB: PublicContractsDB,
85
86
  globalVariables: GlobalVariables,
86
87
  doMerkleOperations: boolean,
87
88
  skipFeeEnforcement: boolean,
88
89
  telemetryClient: TelemetryClient,
89
90
  ) {
90
91
  return new PublicTxSimulator(
91
- db,
92
- worldStateDB,
92
+ treesDB,
93
+ contractsDB,
93
94
  globalVariables,
94
95
  doMerkleOperations,
95
96
  skipFeeEnforcement,
@@ -112,9 +113,9 @@ class PublicProcessorTimeoutError extends Error {
112
113
  export class PublicProcessor implements Traceable {
113
114
  private metrics: PublicProcessorMetrics;
114
115
  constructor(
115
- protected db: MerkleTreeWriteOperations,
116
116
  protected globalVariables: GlobalVariables,
117
- protected worldStateDB: WorldStateDB,
117
+ protected treesDB: PublicTreesDB,
118
+ protected contractsDB: PublicContractsDB,
118
119
  protected publicTxSimulator: PublicTxSimulator,
119
120
  private dateProvider: DateProvider,
120
121
  telemetryClient: TelemetryClient = getTelemetryClient(),
@@ -222,7 +223,7 @@ export class PublicProcessor implements Traceable {
222
223
  // We checkpoint the transaction here, then within the try/catch we
223
224
  // 1. Revert the checkpoint if the tx fails or needs to be discarded for any reason
224
225
  // 2. Commit the transaction in the finally block. Note that by using the ForkCheckpoint lifecycle only the first commit/revert takes effect
225
- const checkpoint = await ForkCheckpoint.new(this.worldStateDB);
226
+ const checkpoint = await ForkCheckpoint.new(this.treesDB);
226
227
 
227
228
  try {
228
229
  const [processedTx, returnValues] = await this.processTx(tx, deadline);
@@ -267,8 +268,8 @@ export class PublicProcessor implements Traceable {
267
268
  await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
268
269
  // Add any contracts registered/deployed in this private-only tx to the block-level cache
269
270
  // (add to tx-level cache and then commit to block-level cache)
270
- await this.worldStateDB.addNewContracts(tx);
271
- this.worldStateDB.commitContractsForTx();
271
+ await this.contractsDB.addNewContracts(tx);
272
+ this.contractsDB.commitContractsForTx();
272
273
  }
273
274
 
274
275
  nullifierCache?.addNullifiers(processedTx.txEffect.nullifiers.map(n => n.toBuffer()));
@@ -294,7 +295,7 @@ export class PublicProcessor implements Traceable {
294
295
  // Base case is we always commit the checkpoint. Using the ForkCheckpoint means this has no effect if the tx was reverted
295
296
  await checkpoint.commit();
296
297
  // The tx-level contracts cache should not live on to the next tx
297
- this.worldStateDB.clearContractsForTx();
298
+ this.contractsDB.clearContractsForTx();
298
299
  }
299
300
  }
300
301
 
@@ -353,12 +354,12 @@ export class PublicProcessor implements Traceable {
353
354
  // b) always had a txHandler with the same db passed to it as this.db, which updated the db in buildBaseRollupHints in this loop
354
355
  // To see how this ^ happens, move back to one shared db in test_context and run orchestrator_multi_public_functions.test.ts
355
356
  // The below is taken from buildBaseRollupHints:
356
- await this.db.appendLeaves(
357
+ await this.treesDB.appendLeaves(
357
358
  MerkleTreeId.NOTE_HASH_TREE,
358
359
  padArrayEnd(processedTx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
359
360
  );
360
361
  try {
361
- await this.db.batchInsert(
362
+ await this.treesDB.batchInsert(
362
363
  MerkleTreeId.NULLIFIER_TREE,
363
364
  padArrayEnd(processedTx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()),
364
365
  NULLIFIER_SUBTREE_HEIGHT,
@@ -374,7 +375,7 @@ export class PublicProcessor implements Traceable {
374
375
  }
375
376
 
376
377
  // The only public data write should be for fee payment
377
- await this.db.sequentialInsert(
378
+ await this.treesDB.sequentialInsert(
378
379
  MerkleTreeId.PUBLIC_DATA_TREE,
379
380
  processedTx.txEffect.publicDataWrites.map(x => x.toBuffer()),
380
381
  );
@@ -426,7 +427,7 @@ export class PublicProcessor implements Traceable {
426
427
 
427
428
  this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${feePayer}`);
428
429
 
429
- const balance = await this.worldStateDB.storageRead(feeJuiceAddress, balanceSlot);
430
+ const balance = await this.treesDB.storageRead(feeJuiceAddress, balanceSlot);
430
431
 
431
432
  if (balance.lt(txFee)) {
432
433
  throw new Error(
@@ -435,7 +436,7 @@ export class PublicProcessor implements Traceable {
435
436
  }
436
437
 
437
438
  const updatedBalance = balance.sub(txFee);
438
- await this.worldStateDB.storageWrite(feeJuiceAddress, balanceSlot, updatedBalance);
439
+ await this.treesDB.storageWrite(feeJuiceAddress, balanceSlot, updatedBalance);
439
440
 
440
441
  return new PublicDataWrite(leafSlot, updatedBalance);
441
442
  }