@aztec-labs/simulator 6.0.0-nightly.20260829

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 (215) hide show
  1. package/README.md +57 -0
  2. package/dest/client.d.ts +6 -0
  3. package/dest/client.d.ts.map +1 -0
  4. package/dest/client.js +3 -0
  5. package/dest/common/errors.d.ts +51 -0
  6. package/dest/common/errors.d.ts.map +1 -0
  7. package/dest/common/errors.js +154 -0
  8. package/dest/common/index.d.ts +3 -0
  9. package/dest/common/index.d.ts.map +1 -0
  10. package/dest/common/index.js +2 -0
  11. package/dest/common/stats/index.d.ts +2 -0
  12. package/dest/common/stats/index.d.ts.map +1 -0
  13. package/dest/common/stats/index.js +1 -0
  14. package/dest/common/stats/stats.d.ts +4 -0
  15. package/dest/common/stats/stats.d.ts.map +1 -0
  16. package/dest/common/stats/stats.js +10 -0
  17. package/dest/private/acvm/acvm.d.ts +43 -0
  18. package/dest/private/acvm/acvm.d.ts.map +1 -0
  19. package/dest/private/acvm/acvm.js +65 -0
  20. package/dest/private/acvm/acvm_types.d.ts +10 -0
  21. package/dest/private/acvm/acvm_types.d.ts.map +1 -0
  22. package/dest/private/acvm/acvm_types.js +3 -0
  23. package/dest/private/acvm/deserialize.d.ts +35 -0
  24. package/dest/private/acvm/deserialize.d.ts.map +1 -0
  25. package/dest/private/acvm/deserialize.js +50 -0
  26. package/dest/private/acvm/index.d.ts +5 -0
  27. package/dest/private/acvm/index.d.ts.map +1 -0
  28. package/dest/private/acvm/index.js +4 -0
  29. package/dest/private/acvm/serialize.d.ts +41 -0
  30. package/dest/private/acvm/serialize.d.ts.map +1 -0
  31. package/dest/private/acvm/serialize.js +99 -0
  32. package/dest/private/acvm_native.d.ts +41 -0
  33. package/dest/private/acvm_native.d.ts.map +1 -0
  34. package/dest/private/acvm_native.js +147 -0
  35. package/dest/private/acvm_wasm.d.ts +16 -0
  36. package/dest/private/acvm_wasm.d.ts.map +1 -0
  37. package/dest/private/acvm_wasm.js +67 -0
  38. package/dest/private/acvm_wasm_with_blobs.d.ts +20 -0
  39. package/dest/private/acvm_wasm_with_blobs.d.ts.map +1 -0
  40. package/dest/private/acvm_wasm_with_blobs.js +35 -0
  41. package/dest/private/circuit_simulator.d.ts +35 -0
  42. package/dest/private/circuit_simulator.d.ts.map +1 -0
  43. package/dest/private/circuit_simulator.js +43 -0
  44. package/dest/private/factory.d.ts +12 -0
  45. package/dest/private/factory.d.ts.map +1 -0
  46. package/dest/private/factory.js +30 -0
  47. package/dest/public/avm/testing/account_proof_fetcher.d.ts +2 -0
  48. package/dest/public/avm/testing/account_proof_fetcher.d.ts.map +1 -0
  49. package/dest/public/avm/testing/account_proof_fetcher.js +152 -0
  50. package/dest/public/avm/testing/base_avm_simulation_tester.d.ts +39 -0
  51. package/dest/public/avm/testing/base_avm_simulation_tester.d.ts.map +1 -0
  52. package/dest/public/avm/testing/base_avm_simulation_tester.js +121 -0
  53. package/dest/public/avm/testing/utils.d.ts +32 -0
  54. package/dest/public/avm/testing/utils.d.ts.map +1 -0
  55. package/dest/public/avm/testing/utils.js +66 -0
  56. package/dest/public/avm_simulator.d.ts +28 -0
  57. package/dest/public/avm_simulator.d.ts.map +1 -0
  58. package/dest/public/avm_simulator.js +4 -0
  59. package/dest/public/avm_simulator_pool.d.ts +84 -0
  60. package/dest/public/avm_simulator_pool.d.ts.map +1 -0
  61. package/dest/public/avm_simulator_pool.js +311 -0
  62. package/dest/public/cdb_ipc_server.d.ts +40 -0
  63. package/dest/public/cdb_ipc_server.d.ts.map +1 -0
  64. package/dest/public/cdb_ipc_server.js +153 -0
  65. package/dest/public/contracts_db_checkpoint.d.ts +16 -0
  66. package/dest/public/contracts_db_checkpoint.d.ts.map +1 -0
  67. package/dest/public/contracts_db_checkpoint.js +30 -0
  68. package/dest/public/db_interfaces.d.ts +68 -0
  69. package/dest/public/db_interfaces.d.ts.map +1 -0
  70. package/dest/public/db_interfaces.js +3 -0
  71. package/dest/public/executor_metrics.d.ts +21 -0
  72. package/dest/public/executor_metrics.d.ts.map +1 -0
  73. package/dest/public/executor_metrics.js +64 -0
  74. package/dest/public/executor_metrics_interface.d.ts +10 -0
  75. package/dest/public/executor_metrics_interface.d.ts.map +1 -0
  76. package/dest/public/executor_metrics_interface.js +1 -0
  77. package/dest/public/fixtures/amm_test.d.ts +10 -0
  78. package/dest/public/fixtures/amm_test.d.ts.map +1 -0
  79. package/dest/public/fixtures/amm_test.js +213 -0
  80. package/dest/public/fixtures/bulk_test.d.ts +6 -0
  81. package/dest/public/fixtures/bulk_test.d.ts.map +1 -0
  82. package/dest/public/fixtures/bulk_test.js +289 -0
  83. package/dest/public/fixtures/custom_bytecode_tester.d.ts +34 -0
  84. package/dest/public/fixtures/custom_bytecode_tester.d.ts.map +1 -0
  85. package/dest/public/fixtures/custom_bytecode_tester.js +53 -0
  86. package/dest/public/fixtures/index.d.ts +10 -0
  87. package/dest/public/fixtures/index.d.ts.map +1 -0
  88. package/dest/public/fixtures/index.js +9 -0
  89. package/dest/public/fixtures/public_processor_test_env.d.ts +30 -0
  90. package/dest/public/fixtures/public_processor_test_env.d.ts.map +1 -0
  91. package/dest/public/fixtures/public_processor_test_env.js +73 -0
  92. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +77 -0
  93. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -0
  94. package/dest/public/fixtures/public_tx_simulation_tester.js +176 -0
  95. package/dest/public/fixtures/simple_contract_data_source.d.ts +36 -0
  96. package/dest/public/fixtures/simple_contract_data_source.d.ts.map +1 -0
  97. package/dest/public/fixtures/simple_contract_data_source.js +95 -0
  98. package/dest/public/fixtures/token_test.d.ts +12 -0
  99. package/dest/public/fixtures/token_test.d.ts.map +1 -0
  100. package/dest/public/fixtures/token_test.js +96 -0
  101. package/dest/public/fixtures/utils.d.ts +26 -0
  102. package/dest/public/fixtures/utils.d.ts.map +1 -0
  103. package/dest/public/fixtures/utils.js +170 -0
  104. package/dest/public/fuzzing/avm_fuzzer_simulator.d.ts +65 -0
  105. package/dest/public/fuzzing/avm_fuzzer_simulator.d.ts.map +1 -0
  106. package/dest/public/fuzzing/avm_fuzzer_simulator.js +181 -0
  107. package/dest/public/fuzzing/avm_simulator_bin.d.ts +2 -0
  108. package/dest/public/fuzzing/avm_simulator_bin.d.ts.map +1 -0
  109. package/dest/public/fuzzing/avm_simulator_bin.js +108 -0
  110. package/dest/public/index.d.ts +10 -0
  111. package/dest/public/index.d.ts.map +1 -0
  112. package/dest/public/index.js +6 -0
  113. package/dest/public/public_db_sources.d.ts +83 -0
  114. package/dest/public/public_db_sources.d.ts.map +1 -0
  115. package/dest/public/public_db_sources.js +297 -0
  116. package/dest/public/public_errors.d.ts +12 -0
  117. package/dest/public/public_errors.d.ts.map +1 -0
  118. package/dest/public/public_errors.js +13 -0
  119. package/dest/public/public_processor/guarded_merkle_tree.d.ts +52 -0
  120. package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -0
  121. package/dest/public/public_processor/guarded_merkle_tree.js +116 -0
  122. package/dest/public/public_processor/public_processor.d.ts +71 -0
  123. package/dest/public/public_processor/public_processor.d.ts.map +1 -0
  124. package/dest/public/public_processor/public_processor.js +858 -0
  125. package/dest/public/public_processor/public_processor_metrics.d.ts +30 -0
  126. package/dest/public/public_processor/public_processor_metrics.d.ts.map +1 -0
  127. package/dest/public/public_processor/public_processor_metrics.js +116 -0
  128. package/dest/public/public_tx_simulator/dumping_public_tx_simulator.d.ts +17 -0
  129. package/dest/public/public_tx_simulator/dumping_public_tx_simulator.d.ts.map +1 -0
  130. package/dest/public/public_tx_simulator/dumping_public_tx_simulator.js +39 -0
  131. package/dest/public/public_tx_simulator/factories.d.ts +14 -0
  132. package/dest/public/public_tx_simulator/factories.d.ts.map +1 -0
  133. package/dest/public/public_tx_simulator/factories.js +28 -0
  134. package/dest/public/public_tx_simulator/index.d.ts +6 -0
  135. package/dest/public/public_tx_simulator/index.d.ts.map +1 -0
  136. package/dest/public/public_tx_simulator/index.js +3 -0
  137. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +53 -0
  138. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -0
  139. package/dest/public/public_tx_simulator/public_tx_simulator.js +127 -0
  140. package/dest/public/public_tx_simulator/public_tx_simulator_base.d.ts +24 -0
  141. package/dest/public/public_tx_simulator/public_tx_simulator_base.d.ts.map +1 -0
  142. package/dest/public/public_tx_simulator/public_tx_simulator_base.js +31 -0
  143. package/dest/public/public_tx_simulator/public_tx_simulator_interface.d.ts +32 -0
  144. package/dest/public/public_tx_simulator/public_tx_simulator_interface.d.ts.map +1 -0
  145. package/dest/public/public_tx_simulator/public_tx_simulator_interface.js +1 -0
  146. package/dest/public/side_effect_errors.d.ts +44 -0
  147. package/dest/public/side_effect_errors.d.ts.map +1 -0
  148. package/dest/public/side_effect_errors.js +75 -0
  149. package/dest/public/test_executor_metrics.d.ts +56 -0
  150. package/dest/public/test_executor_metrics.d.ts.map +1 -0
  151. package/dest/public/test_executor_metrics.js +305 -0
  152. package/dest/public/unique_class_ids.d.ts +37 -0
  153. package/dest/public/unique_class_ids.d.ts.map +1 -0
  154. package/dest/public/unique_class_ids.js +61 -0
  155. package/dest/public/utils.d.ts +3 -0
  156. package/dest/public/utils.d.ts.map +1 -0
  157. package/dest/public/utils.js +18 -0
  158. package/dest/server.d.ts +7 -0
  159. package/dest/server.d.ts.map +1 -0
  160. package/dest/server.js +5 -0
  161. package/package.json +109 -0
  162. package/src/client.ts +5 -0
  163. package/src/common/errors.ts +219 -0
  164. package/src/common/index.ts +2 -0
  165. package/src/common/stats/index.ts +1 -0
  166. package/src/common/stats/stats.ts +20 -0
  167. package/src/private/acvm/acvm.ts +114 -0
  168. package/src/private/acvm/acvm_types.ts +11 -0
  169. package/src/private/acvm/deserialize.ts +58 -0
  170. package/src/private/acvm/index.ts +4 -0
  171. package/src/private/acvm/serialize.ts +123 -0
  172. package/src/private/acvm_native.ts +200 -0
  173. package/src/private/acvm_wasm.ts +80 -0
  174. package/src/private/acvm_wasm_with_blobs.ts +55 -0
  175. package/src/private/circuit_simulator.ts +91 -0
  176. package/src/private/factory.ts +40 -0
  177. package/src/public/avm/testing/account_proof.json +553 -0
  178. package/src/public/avm/testing/account_proof_fetcher.ts +166 -0
  179. package/src/public/avm/testing/base_avm_simulation_tester.ts +162 -0
  180. package/src/public/avm/testing/utils.ts +114 -0
  181. package/src/public/avm_simulator.ts +29 -0
  182. package/src/public/avm_simulator_pool.ts +355 -0
  183. package/src/public/cdb_ipc_server.ts +198 -0
  184. package/src/public/contracts_db_checkpoint.ts +41 -0
  185. package/src/public/db_interfaces.ts +76 -0
  186. package/src/public/executor_metrics.ts +102 -0
  187. package/src/public/executor_metrics_interface.ts +20 -0
  188. package/src/public/fixtures/amm_test.ts +331 -0
  189. package/src/public/fixtures/bulk_test.ts +194 -0
  190. package/src/public/fixtures/custom_bytecode_tester.ts +83 -0
  191. package/src/public/fixtures/index.ts +13 -0
  192. package/src/public/fixtures/public_processor_test_env.ts +88 -0
  193. package/src/public/fixtures/public_tx_simulation_tester.ts +315 -0
  194. package/src/public/fixtures/simple_contract_data_source.ts +122 -0
  195. package/src/public/fixtures/token_test.ts +148 -0
  196. package/src/public/fixtures/utils.ts +269 -0
  197. package/src/public/fuzzing/avm_fuzzer_simulator.ts +302 -0
  198. package/src/public/fuzzing/avm_simulator_bin.ts +156 -0
  199. package/src/public/index.ts +16 -0
  200. package/src/public/public_db_sources.ts +405 -0
  201. package/src/public/public_errors.ts +14 -0
  202. package/src/public/public_processor/guarded_merkle_tree.ts +161 -0
  203. package/src/public/public_processor/public_processor.ts +657 -0
  204. package/src/public/public_processor/public_processor_metrics.ts +138 -0
  205. package/src/public/public_tx_simulator/dumping_public_tx_simulator.ts +66 -0
  206. package/src/public/public_tx_simulator/factories.ts +61 -0
  207. package/src/public/public_tx_simulator/index.ts +8 -0
  208. package/src/public/public_tx_simulator/public_tx_simulator.ts +190 -0
  209. package/src/public/public_tx_simulator/public_tx_simulator_base.ts +37 -0
  210. package/src/public/public_tx_simulator/public_tx_simulator_interface.ts +33 -0
  211. package/src/public/side_effect_errors.ts +96 -0
  212. package/src/public/test_executor_metrics.ts +399 -0
  213. package/src/public/unique_class_ids.ts +79 -0
  214. package/src/public/utils.ts +16 -0
  215. package/src/server.ts +6 -0
@@ -0,0 +1,405 @@
1
+ import {
2
+ L1_TO_L2_MSG_TREE_LEAF_COUNT,
3
+ NOTE_HASH_TREE_LEAF_COUNT,
4
+ NULLIFIER_SUBTREE_HEIGHT,
5
+ PUBLIC_DATA_SUBTREE_HEIGHT,
6
+ } from '@aztec-labs/constants';
7
+ import { Fr } from '@aztec-labs/foundation/curves/bn254';
8
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec-labs/foundation/log';
9
+ import { Timer } from '@aztec-labs/foundation/timer';
10
+ import { ContractClassPublishedEvent } from '@aztec-labs/protocol-contracts/class-registry';
11
+ import { ContractInstancePublishedEvent } from '@aztec-labs/protocol-contracts/instance-registry';
12
+ import type { FunctionSelector } from '@aztec-labs/stdlib/abi';
13
+ import { PublicDataWrite } from '@aztec-labs/stdlib/avm';
14
+ import type { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
15
+ import {
16
+ AllContractDeploymentData,
17
+ type ContractClassPublic,
18
+ type ContractDataSource,
19
+ type ContractDeploymentData,
20
+ type ContractInstanceWithAddress,
21
+ computePublicBytecodeCommitment,
22
+ } from '@aztec-labs/stdlib/contract';
23
+ import { computePublicDataTreeLeafSlot } from '@aztec-labs/stdlib/hash';
24
+ import type { MerkleTreeWriteOperations } from '@aztec-labs/stdlib/interfaces/server';
25
+ import type { PublicDBAccessStats } from '@aztec-labs/stdlib/stats';
26
+ import {
27
+ MerkleTreeId,
28
+ NullifierLeaf,
29
+ PublicDataTreeLeaf,
30
+ type PublicDataTreeLeafPreimage,
31
+ getTreeName,
32
+ } from '@aztec-labs/stdlib/trees';
33
+ import { TreeSnapshots, type Tx } from '@aztec-labs/stdlib/tx';
34
+ import type { UInt64 } from '@aztec-labs/stdlib/types';
35
+ import { strict as assert } from 'assert';
36
+
37
+ import { ContractsDbCheckpoint } from './contracts_db_checkpoint.js';
38
+ import type { PublicContractsDBInterface, PublicStateDBInterface } from './db_interfaces.js';
39
+ import { L1ToL2MessageIndexOutOfRangeError, NoteHashIndexOutOfRangeError } from './side_effect_errors.js';
40
+
41
+ /**
42
+ * Implements the PublicContractsDBInterface using a ContractDataSource.
43
+ * Uses a stack-based checkpoint model for managing contract state.
44
+ */
45
+ export class PublicContractsDB implements PublicContractsDBInterface {
46
+ private contractStateStack: ContractsDbCheckpoint[] = [new ContractsDbCheckpoint()];
47
+
48
+ private log: Logger;
49
+
50
+ constructor(
51
+ private dataSource: ContractDataSource,
52
+ bindings?: LoggerBindings,
53
+ ) {
54
+ this.log = createLogger('simulator:contracts-data-source', bindings);
55
+ }
56
+
57
+ /** Parses raw contract deployment data and inserts the resulting contracts into the current checkpoint. */
58
+ public addContractsFromLogs(contractDeploymentData: ContractDeploymentData): void {
59
+ const currentState = this.getCurrentState();
60
+
61
+ this.addContractClassesFromEvents(
62
+ ContractClassPublishedEvent.extractContractClassEvents(contractDeploymentData.getContractClassLogs()),
63
+ currentState,
64
+ );
65
+
66
+ this.addContractInstancesFromEvents(
67
+ ContractInstancePublishedEvent.extractContractInstanceEvents(contractDeploymentData.getPrivateLogs()),
68
+ currentState,
69
+ );
70
+ }
71
+
72
+ public addNewContracts(tx: Tx): void {
73
+ const contractDeploymentData = AllContractDeploymentData.fromTx(tx);
74
+ this.addContractsFromLogs(contractDeploymentData.getNonRevertibleContractDeploymentData());
75
+ this.addContractsFromLogs(contractDeploymentData.getRevertibleContractDeploymentData());
76
+ }
77
+
78
+ /** Inserts typed contract instances directly into the current checkpoint. */
79
+ public addContracts(contractInstances?: ContractInstanceWithAddress[]): void {
80
+ const currentState = this.getCurrentState();
81
+ for (const instance of contractInstances ?? []) {
82
+ currentState.addInstance(instance.address, instance);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Creates a new checkpoint, copying the current state for upcoming modifications,
88
+ * and enabling rollbacks to current state in case of a revert.
89
+ */
90
+ public createCheckpoint(): void {
91
+ const currentState = this.getCurrentState();
92
+ const newState = currentState.fork();
93
+ this.contractStateStack.push(newState);
94
+ }
95
+
96
+ /**
97
+ * Commits the current checkpoint, accepting its state latest.
98
+ */
99
+ public commitCheckpoint(): void {
100
+ if (this.contractStateStack.length <= 1) {
101
+ throw new Error('No checkpoint to commit');
102
+ }
103
+ const topState = this.contractStateStack.pop()!;
104
+ this.contractStateStack[this.contractStateStack.length - 1] = topState;
105
+ }
106
+
107
+ /**
108
+ * Commits the current checkpoint, not erroring if there is no checkpoint
109
+ * to commit. This is useful to do a sanity commit at the end of tx execution,
110
+ * doing nothing if the checkpoint was already reverted, but truly committing
111
+ * otherwise.
112
+ */
113
+ public commitCheckpointOkIfNone(): void {
114
+ if (this.contractStateStack.length <= 1) {
115
+ return;
116
+ }
117
+ const topState = this.contractStateStack.pop()!;
118
+ this.contractStateStack[this.contractStateStack.length - 1] = topState;
119
+ }
120
+
121
+ /**
122
+ * Reverts the current checkpoint, discarding its state and rolling back
123
+ * to the state as of the latest checkpoint.
124
+ */
125
+ public revertCheckpoint(): void {
126
+ if (this.contractStateStack.length <= 1) {
127
+ throw new Error('No checkpoint to revert');
128
+ }
129
+ this.contractStateStack.pop();
130
+ }
131
+
132
+ private getCurrentState(): ContractsDbCheckpoint {
133
+ return this.contractStateStack[this.contractStateStack.length - 1];
134
+ }
135
+
136
+ // TODO(fcarreiro/alvaro): This method currently needs a blockNumber. Since this class
137
+ // is only ever used for a given block, it should be possible to construct it with the
138
+ // block number and then forget about it. However, since this class (and interface) is
139
+ // currently more externally exposed than we'd want to, Facundo preferred to not add it
140
+ // to the constructor right now. If we can make this class more private, we should
141
+ // reconsider this. A litmus test is in how many places we need to initialize with a
142
+ // dummy block number (tests or not) and pass block numbers to `super`.
143
+ // Note: Block number got changed to timestamp so this comment ^ is outdated. Keeping
144
+ // the comment as is as I am not part of the AVM cabal.
145
+ public async getContractInstance(
146
+ address: AztecAddress,
147
+ timestamp: UInt64,
148
+ ): Promise<ContractInstanceWithAddress | undefined> {
149
+ const currentState = this.getCurrentState();
150
+ return currentState.getInstance(address) ?? (await this.dataSource.getContract(address, timestamp));
151
+ }
152
+
153
+ public async getContractClass(contractClassId: Fr): Promise<ContractClassPublic | undefined> {
154
+ const currentState = this.getCurrentState();
155
+ return currentState.getClass(contractClassId) ?? (await this.dataSource.getContractClass(contractClassId));
156
+ }
157
+
158
+ public async getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
159
+ const currentState = this.getCurrentState();
160
+ const commitment =
161
+ currentState.getBytecodeCommitment(contractClassId) ??
162
+ (await this.dataSource.getBytecodeCommitment(contractClassId));
163
+ if (commitment !== undefined) {
164
+ return commitment;
165
+ }
166
+ // Not in the current state or the store, compute it here
167
+ // Get the contract class
168
+ const contractClass = await this.getContractClass(contractClassId);
169
+
170
+ if (contractClass === undefined) {
171
+ // cannot compute bytecode commitment if contract class is not found
172
+ return undefined;
173
+ }
174
+
175
+ const value = await computePublicBytecodeCommitment(contractClass.packedBytecode);
176
+ // Add to cache (current checkpoint state) so we don't compute again
177
+ currentState.addBytecodeCommitment(contractClassId, value);
178
+ return value;
179
+ }
180
+
181
+ public async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
182
+ return await this.dataSource.getDebugFunctionName(address, selector);
183
+ }
184
+
185
+ private addContractClassesFromEvents(
186
+ contractClassEvents: ContractClassPublishedEvent[],
187
+ state: ContractsDbCheckpoint,
188
+ ) {
189
+ for (const event of contractClassEvents) {
190
+ this.log.debug(`Adding class ${event.contractClassId.toString()} to contract state`);
191
+ const contractClass = event.toContractClassPublic();
192
+ state.addClass(event.contractClassId, contractClass);
193
+ }
194
+ }
195
+
196
+ private addContractInstancesFromEvents(
197
+ contractInstanceEvents: ContractInstancePublishedEvent[],
198
+ state: ContractsDbCheckpoint,
199
+ ) {
200
+ contractInstanceEvents.forEach(e => {
201
+ this.log.debug(
202
+ `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to contract state`,
203
+ );
204
+ state.addInstance(e.address, e.toContractInstance());
205
+ });
206
+ }
207
+ }
208
+
209
+ /**
210
+ * A high-level class that provides access to the merkle trees.
211
+ *
212
+ * This class is just a helper wrapper around a merkle db. Anything that you can do with it
213
+ * can also be done directly with the merkle db. This class should NOT be exposed or used
214
+ * outside of `simulator/src/public`.
215
+ *
216
+ * NOTE: This class is currently written in such a way that it would generate the
217
+ * necessary hints if used with a hinting merkle db. This is a bit of a leak of concepts.
218
+ * Eventually we can have everything depend on a config/factory at the TxSimulator level
219
+ * to decide whether to use hints or not (same with tracing, etc).
220
+ */
221
+ export class PublicTreesDB implements PublicStateDBInterface {
222
+ private logger: Logger;
223
+
224
+ constructor(
225
+ private readonly db: MerkleTreeWriteOperations,
226
+ bindings?: LoggerBindings,
227
+ ) {
228
+ this.logger = createLogger('simulator:public-trees-db', bindings);
229
+ }
230
+
231
+ public async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
232
+ const timer = new Timer();
233
+ const leafSlot = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
234
+
235
+ const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
236
+ if (!lowLeafResult) {
237
+ throw new Error('Low leaf not found');
238
+ }
239
+
240
+ // TODO: We need this for the hints. See class comment for more details.
241
+ await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
242
+ // Unconditionally fetching the preimage for the hints. Move it to the hinting layer?
243
+ const preimage = (await this.db.getLeafPreimage(
244
+ MerkleTreeId.PUBLIC_DATA_TREE,
245
+ lowLeafResult.index,
246
+ )) as PublicDataTreeLeafPreimage;
247
+
248
+ const result = lowLeafResult.alreadyPresent ? preimage.leaf.value : Fr.ZERO;
249
+ this.logger.debug(`Storage read (contract=${contract}, slot=${slot}, value=${result})`, {
250
+ eventName: 'public-db-access',
251
+ duration: timer.ms(),
252
+ operation: 'storage-read',
253
+ } satisfies PublicDBAccessStats);
254
+
255
+ return result;
256
+ }
257
+
258
+ public async storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<void> {
259
+ const timer = new Timer();
260
+ const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
261
+ const publicDataWrite = new PublicDataWrite(leafSlot, newValue);
262
+ await this.db.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, [publicDataWrite.toBuffer()]);
263
+
264
+ this.logger.debug(`Storage write (contract=${contract}, slot=${slot}, value=${newValue})`, {
265
+ eventName: 'public-db-access',
266
+ duration: timer.ms(),
267
+ operation: 'storage-write',
268
+ } satisfies PublicDBAccessStats);
269
+ }
270
+
271
+ public async getL1ToL2LeafValue(leafIndex: bigint): Promise<Fr> {
272
+ const timer = new Timer();
273
+ if (leafIndex > L1_TO_L2_MSG_TREE_LEAF_COUNT) {
274
+ throw new L1ToL2MessageIndexOutOfRangeError(Number(leafIndex));
275
+ }
276
+ const leafValue = await this.db.getLeafValue(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
277
+ assert(leafValue !== undefined, 'Unexpected null response from l1 to l2 message tree');
278
+ // TODO: We need this for the hints. See class comment for more details.
279
+ await this.db.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex);
280
+
281
+ this.logger.debug(`Fetched L1 to L2 message leaf value (leafIndex=${leafIndex}, value=${leafValue})`, {
282
+ eventName: 'public-db-access',
283
+ duration: timer.ms(),
284
+ operation: 'get-l1-to-l2-message-leaf-value',
285
+ } satisfies PublicDBAccessStats);
286
+ return leafValue;
287
+ }
288
+
289
+ public async getNoteHash(leafIndex: bigint): Promise<Fr> {
290
+ const timer = new Timer();
291
+ if (leafIndex > NOTE_HASH_TREE_LEAF_COUNT) {
292
+ throw new NoteHashIndexOutOfRangeError(Number(leafIndex));
293
+ }
294
+ const leafValue = await this.db.getLeafValue(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
295
+ assert(leafValue !== undefined, 'Unexpected null response from note hash tree');
296
+ // TODO: We need this for the hints. See class comment for more details.
297
+ await this.db.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
298
+
299
+ this.logger.debug(`Fetched note hash leaf value (leafIndex=${leafIndex}, value=${leafValue})`, {
300
+ eventName: 'public-db-access',
301
+ duration: timer.ms(),
302
+ operation: 'get-note-hash',
303
+ } satisfies PublicDBAccessStats);
304
+ return leafValue;
305
+ }
306
+
307
+ public async writeNoteHash(noteHash: Fr): Promise<void> {
308
+ const timer = new Timer();
309
+ await this.db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [noteHash]);
310
+
311
+ this.logger.debug(`Wrote note hash (noteHash=${noteHash})`, {
312
+ eventName: 'public-db-access',
313
+ duration: timer.ms(),
314
+ operation: 'write-note-hash',
315
+ } satisfies PublicDBAccessStats);
316
+ }
317
+
318
+ public async checkNullifierExists(nullifier: Fr): Promise<boolean> {
319
+ const timer = new Timer();
320
+ const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
321
+ if (!lowLeafResult) {
322
+ throw new Error('Low leaf not found');
323
+ }
324
+ // TODO: We need this for the hints. See class comment for more details.
325
+ await this.db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
326
+ // TODO: We need this for the hints. See class comment for more details.
327
+ await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, lowLeafResult.index);
328
+ const exists = lowLeafResult.alreadyPresent;
329
+
330
+ this.logger.debug(`Checked nullifier exists (nullifier=${nullifier}, exists=${exists})`, {
331
+ eventName: 'public-db-access',
332
+ duration: timer.ms(),
333
+ operation: 'check-nullifier-exists',
334
+ } satisfies PublicDBAccessStats);
335
+ return exists;
336
+ }
337
+
338
+ public async writeNullifier(siloedNullifier: Fr): Promise<void> {
339
+ const timer = new Timer();
340
+ await this.db.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()]);
341
+
342
+ this.logger.debug(`Wrote nullifier (nullifier=${siloedNullifier})`, {
343
+ eventName: 'public-db-access',
344
+ duration: timer.ms(),
345
+ operation: 'write-nullifier',
346
+ } satisfies PublicDBAccessStats);
347
+ }
348
+
349
+ public async padTree(treeId: MerkleTreeId, leavesToInsert: number): Promise<void> {
350
+ const timer = new Timer();
351
+
352
+ switch (treeId) {
353
+ // Indexed trees.
354
+ case MerkleTreeId.NULLIFIER_TREE:
355
+ await this.db.batchInsert(
356
+ treeId,
357
+ Array(leavesToInsert).fill(NullifierLeaf.empty().toBuffer()),
358
+ NULLIFIER_SUBTREE_HEIGHT,
359
+ );
360
+ break;
361
+ case MerkleTreeId.PUBLIC_DATA_TREE:
362
+ await this.db.batchInsert(
363
+ treeId,
364
+ Array(leavesToInsert).fill(PublicDataTreeLeaf.empty().toBuffer()),
365
+ PUBLIC_DATA_SUBTREE_HEIGHT,
366
+ );
367
+ break;
368
+ // Append-only trees.
369
+ case MerkleTreeId.L1_TO_L2_MESSAGE_TREE:
370
+ case MerkleTreeId.NOTE_HASH_TREE:
371
+ await this.db.appendLeaves(treeId, Array(leavesToInsert).fill(Fr.ZERO));
372
+ break;
373
+ default:
374
+ throw new Error(`Padding not supported for tree ${treeId}`);
375
+ }
376
+
377
+ this.logger.debug(`Padded tree (tree=${getTreeName(treeId)}, leavesToInsert=${leavesToInsert})`, {
378
+ eventName: 'public-db-access',
379
+ duration: timer.ms(),
380
+ operation: 'pad-tree',
381
+ } satisfies PublicDBAccessStats);
382
+ }
383
+
384
+ public async createCheckpoint(): Promise<void> {
385
+ await this.db.createCheckpoint();
386
+ }
387
+
388
+ public async commitCheckpoint(): Promise<void> {
389
+ await this.db.commitCheckpoint();
390
+ }
391
+
392
+ public async revertCheckpoint(): Promise<void> {
393
+ await this.db.revertCheckpoint();
394
+ }
395
+
396
+ public async getTreeSnapshots(): Promise<TreeSnapshots> {
397
+ const stateReference = await this.db.getStateReference();
398
+ return new TreeSnapshots(
399
+ stateReference.l1ToL2MessageTree,
400
+ stateReference.partial.noteHashTree,
401
+ stateReference.partial.nullifierTree,
402
+ stateReference.partial.publicDataTree,
403
+ );
404
+ }
405
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Any known (and checked) error that can be thrown during public execution.
3
+ * Includes AvmExecutionErrors and SideEffectErrors.
4
+ *
5
+ * AvmSimulator catches any checked errors before returning a boolean "reverted".
6
+ * Unchecked errors are generally the result of a bug. They are propagated and
7
+ * ultimately will be the resonsibility of PublicProcessor to handle.
8
+ */
9
+ export abstract class CheckedPublicExecutionError extends Error {
10
+ constructor(message: string) {
11
+ super(message);
12
+ this.name = 'CheckedPublicExecutionError';
13
+ }
14
+ }
@@ -0,0 +1,161 @@
1
+ import type { BlockNumber } from '@aztec-labs/foundation/branded-types';
2
+ import { SerialQueue } from '@aztec-labs/foundation/queue';
3
+ import type { IndexedTreeLeafPreimage, SiblingPath } from '@aztec-labs/foundation/trees';
4
+ import type {
5
+ BatchInsertionResult,
6
+ IndexedTreeId,
7
+ MerkleTreeId,
8
+ MerkleTreeLeafType,
9
+ MerkleTreeWriteOperations,
10
+ SequentialInsertionResult,
11
+ TreeHeights,
12
+ TreeInfo,
13
+ } from '@aztec-labs/stdlib/trees';
14
+ import type { BlockHeader, StateReference } from '@aztec-labs/stdlib/tx';
15
+ import type { WorldStateRevision } from '@aztec-labs/stdlib/world-state';
16
+
17
+ /**
18
+ * Wraps an instance of `MerkleTreeWriteOperations` to allow the sequencer to gate access.
19
+ * If transactions execution goes past the deadline, the simulator will continue to execute and update the world state
20
+ * The public processor however requires that the world state remain constant after the deadline in order to finalize the block
21
+ * The public processor provides this implementation of MerkleTreeWriteOperations to the simulator
22
+ */
23
+
24
+ export class GuardedMerkleTreeOperations implements MerkleTreeWriteOperations {
25
+ private isStopped = false;
26
+ private serialQueue = new SerialQueue();
27
+
28
+ constructor(private target: MerkleTreeWriteOperations) {
29
+ this.serialQueue.start();
30
+ }
31
+
32
+ private guard() {
33
+ if (this.isStopped) {
34
+ throw new Error('Merkle tree access has been stopped');
35
+ }
36
+ }
37
+
38
+ // Executes the provided function only if the guard is not stopped.
39
+ private guardAndPush<T>(fn: () => Promise<T>): Promise<T> {
40
+ this.guard();
41
+ return this.serialQueue.put(() => {
42
+ this.guard();
43
+ return fn();
44
+ });
45
+ }
46
+
47
+ public getUnderlyingFork(): MerkleTreeWriteOperations {
48
+ return this.target;
49
+ }
50
+
51
+ // Stops all further access to the merkle trees via this object
52
+ async stop(): Promise<void> {
53
+ await this.serialQueue.put(() => {
54
+ this.isStopped = true;
55
+ return Promise.resolve();
56
+ });
57
+ return this.serialQueue.end();
58
+ }
59
+
60
+ // Proxy all methods to the target
61
+ appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
62
+ return this.guardAndPush(() => this.target.appendLeaves(treeId, leaves));
63
+ }
64
+
65
+ updateArchive(header: BlockHeader): Promise<void> {
66
+ return this.guardAndPush(() => this.target.updateArchive(header));
67
+ }
68
+ batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number, ID extends IndexedTreeId>(
69
+ treeId: ID,
70
+ leaves: Buffer[],
71
+ subtreeHeight: number,
72
+ ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
73
+ return this.guardAndPush(() => this.target.batchInsert(treeId, leaves, subtreeHeight));
74
+ }
75
+ sequentialInsert<TreeHeight extends number, ID extends IndexedTreeId>(
76
+ treeId: ID,
77
+ leaves: Buffer[],
78
+ ): Promise<SequentialInsertionResult<TreeHeight>> {
79
+ return this.guardAndPush(() => this.target.sequentialInsert(treeId, leaves));
80
+ }
81
+ close(): Promise<void> {
82
+ return this.guardAndPush(() => this.target.close());
83
+ }
84
+
85
+ async [Symbol.asyncDispose](): Promise<void> {
86
+ await this.close();
87
+ }
88
+ getTreeInfo(treeId: MerkleTreeId): Promise<TreeInfo> {
89
+ return this.guardAndPush(() => this.target.getTreeInfo(treeId));
90
+ }
91
+ getStateReference(): Promise<StateReference> {
92
+ return this.guardAndPush(() => this.target.getStateReference());
93
+ }
94
+ getInitialHeader(): BlockHeader {
95
+ return this.target.getInitialHeader();
96
+ }
97
+ public getRevision(): WorldStateRevision {
98
+ return this.target.getRevision();
99
+ }
100
+ public getIpcPath(): string {
101
+ return this.target.getIpcPath();
102
+ }
103
+ getSiblingPath<ID extends MerkleTreeId>(treeId: ID, index: bigint): Promise<SiblingPath<TreeHeights[ID]>> {
104
+ return this.guardAndPush(() => this.target.getSiblingPath(treeId, index));
105
+ }
106
+ getPreviousValueIndex<ID extends IndexedTreeId>(
107
+ treeId: ID,
108
+ value: bigint,
109
+ ): Promise<{ index: bigint; alreadyPresent: boolean } | undefined> {
110
+ return this.guardAndPush(() => this.target.getPreviousValueIndex(treeId, value));
111
+ }
112
+ getLeafPreimage<ID extends IndexedTreeId>(treeId: ID, index: bigint): Promise<IndexedTreeLeafPreimage | undefined> {
113
+ return this.guardAndPush(() => this.target.getLeafPreimage(treeId, index));
114
+ }
115
+ findLeafIndices<ID extends MerkleTreeId>(
116
+ treeId: ID,
117
+ values: MerkleTreeLeafType<ID>[],
118
+ ): Promise<(bigint | undefined)[]> {
119
+ return this.guardAndPush(() => this.target.findLeafIndices(treeId, values));
120
+ }
121
+ findLeafIndicesAfter<ID extends MerkleTreeId>(
122
+ treeId: ID,
123
+ values: MerkleTreeLeafType<ID>[],
124
+ startIndex: bigint,
125
+ ): Promise<(bigint | undefined)[]> {
126
+ return this.guardAndPush(() => this.target.findLeafIndicesAfter(treeId, values, startIndex));
127
+ }
128
+ getLeafValue<ID extends MerkleTreeId>(
129
+ treeId: ID,
130
+ index: bigint,
131
+ ): Promise<MerkleTreeLeafType<typeof treeId> | undefined> {
132
+ return this.guardAndPush(() => this.target.getLeafValue(treeId, index));
133
+ }
134
+ getBlockNumbersForLeafIndices<ID extends MerkleTreeId>(
135
+ treeId: ID,
136
+ leafIndices: bigint[],
137
+ ): Promise<(BlockNumber | undefined)[]> {
138
+ return this.guardAndPush(() => this.target.getBlockNumbersForLeafIndices(treeId, leafIndices));
139
+ }
140
+ createCheckpoint(): Promise<number> {
141
+ return this.guardAndPush(() => this.target.createCheckpoint());
142
+ }
143
+ commitCheckpoint(): Promise<void> {
144
+ return this.guardAndPush(() => this.target.commitCheckpoint());
145
+ }
146
+ revertCheckpoint(): Promise<void> {
147
+ return this.guardAndPush(() => this.target.revertCheckpoint());
148
+ }
149
+ commitAllCheckpointsTo(depth: number): Promise<void> {
150
+ return this.guardAndPush(() => this.target.commitAllCheckpointsTo(depth));
151
+ }
152
+ revertAllCheckpointsTo(depth: number): Promise<void> {
153
+ return this.guardAndPush(() => this.target.revertAllCheckpointsTo(depth));
154
+ }
155
+ findSiblingPaths<ID extends MerkleTreeId>(
156
+ treeId: ID,
157
+ values: MerkleTreeLeafType<ID>[],
158
+ ): Promise<({ path: SiblingPath<TreeHeights[ID]>; index: bigint } | undefined)[]> {
159
+ return this.guardAndPush(() => this.target.findSiblingPaths(treeId, values));
160
+ }
161
+ }