@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,83 @@
1
+ import { FunctionType, emptyContractArtifact, emptyFunctionArtifact } from '@aztec-labs/stdlib/abi';
2
+ import type { PublicTxResult } from '@aztec-labs/stdlib/avm';
3
+ import { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
4
+ import type { ContractInstanceWithAddress } from '@aztec-labs/stdlib/contract';
5
+
6
+ import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
7
+
8
+ /**
9
+ * Deploy a contract with the provided bytecode.
10
+ * @param bytecode - The bytecode buffer to use
11
+ * @param tester - The tester to use
12
+ * @param contractName - The name of the contract
13
+ * @param deployer - The deployer address
14
+ * @returns The deployed contract instance
15
+ */
16
+ export async function deployCustomBytecode(
17
+ bytecode: Buffer,
18
+ tester: PublicTxSimulationTester,
19
+ contractName: string = 'CustomBytecodeContract',
20
+ deployer: AztecAddress = AztecAddress.fromNumberUnsafe(42),
21
+ ): Promise<ContractInstanceWithAddress> {
22
+ const contractArtifact = emptyContractArtifact();
23
+ contractArtifact.name = contractName;
24
+ contractArtifact.functions = [emptyFunctionArtifact()];
25
+ // We use name 'public_dispatch' since that is what is expected
26
+ // in a ContractArtifact. But function selectors are not required
27
+ // when executing since the custom bytecode likely has no dispatch.
28
+ contractArtifact.functions[0].name = 'public_dispatch';
29
+ contractArtifact.functions[0].functionType = FunctionType.PUBLIC;
30
+ contractArtifact.functions[0].bytecode = bytecode;
31
+
32
+ // return the contract instance
33
+ return await tester.registerAndDeployContract(
34
+ /*constructorArgs=*/ [],
35
+ deployer,
36
+ /*contractArtifact=*/ contractArtifact,
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Execute a custom bytecode contract.
42
+ * @param contract - The contract instance to execute
43
+ * @param tester - The tester to use
44
+ * @param txLabel - The label of the transaction
45
+ * @param calldata - The calldata to use
46
+ * @returns The execution result
47
+ */
48
+ export async function executeCustomBytecode(
49
+ contract: ContractInstanceWithAddress,
50
+ tester: PublicTxSimulationTester,
51
+ txLabel: string = 'CustomBytecodeTest',
52
+ calldata: any[] = [],
53
+ ): Promise<PublicTxResult> {
54
+ // EXECUTE! This means that if using AvmProvingTester subclass, it will PROVE the transaction!
55
+ return await tester.executeTxWithLabel(
56
+ /*txLabel=*/ txLabel,
57
+ /*sender=*/ contract.deployer,
58
+ /*setupCalls=*/ [],
59
+ /*appCalls=*/ [{ address: contract.address, args: calldata }],
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Deploy and execute a custom bytecode contract.
65
+ * @param bytecode - The bytecode buffer to use
66
+ * @param tester - The tester to use
67
+ * @param txLabel - The label of the transaction
68
+ * @param contractName - The name of the contract
69
+ * @param deployer - The deployer address
70
+ * @param calldata - The calldata to use
71
+ * @returns The execution result
72
+ */
73
+ export async function deployAndExecuteCustomBytecode(
74
+ bytecode: Buffer,
75
+ tester: PublicTxSimulationTester,
76
+ txLabel: string = 'CustomBytecodeTest',
77
+ contractName: string = 'CustomBytecodeContract',
78
+ deployer: AztecAddress = AztecAddress.fromNumberUnsafe(42),
79
+ calldata: any[] = [],
80
+ ): Promise<PublicTxResult> {
81
+ const testContract = await deployCustomBytecode(bytecode, tester, contractName, deployer);
82
+ return await executeCustomBytecode(testContract, tester, txLabel, calldata);
83
+ }
@@ -0,0 +1,13 @@
1
+ export * from './public_tx_simulation_tester.js';
2
+ export * from './public_processor_test_env.js';
3
+ export * from './utils.js';
4
+ export * from './simple_contract_data_source.js';
5
+ export { TestExecutorMetrics } from '../test_executor_metrics.js';
6
+ export { ammTest } from './amm_test.js';
7
+ export { bulkTest, megaBulkTest } from './bulk_test.js';
8
+ export { tokenTest } from './token_test.js';
9
+ export {
10
+ deployCustomBytecode,
11
+ executeCustomBytecode,
12
+ deployAndExecuteCustomBytecode,
13
+ } from './custom_bytecode_tester.js';
@@ -0,0 +1,88 @@
1
+ import { createLogger } from '@aztec-labs/foundation/log';
2
+ import { TestDateProvider } from '@aztec-labs/foundation/timer';
3
+ import { PublicSimulatorConfig } from '@aztec-labs/stdlib/avm';
4
+ import { GasFees } from '@aztec-labs/stdlib/gas';
5
+ import { GlobalVariables } from '@aztec-labs/stdlib/tx';
6
+ import { getTelemetryClient } from '@aztec-labs/telemetry-client';
7
+ import { NativeWorldStateService } from '@aztec-labs/world-state';
8
+
9
+ import { AvmSimulatorPool } from '../avm_simulator_pool.js';
10
+ import { PublicContractsDB } from '../public_db_sources.js';
11
+ import { GuardedMerkleTreeOperations } from '../public_processor/guarded_merkle_tree.js';
12
+ import { PublicProcessor } from '../public_processor/public_processor.js';
13
+ import { PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
14
+ import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
15
+ import { SimpleContractDataSource } from './simple_contract_data_source.js';
16
+
17
+ /** Options for {@link PublicProcessorTestEnv.create}. */
18
+ export interface PublicProcessorTestEnvOptions {
19
+ /** Global variables shared by the processor and the tester. Defaults to empty with nonzero gas fees. */
20
+ globals?: GlobalVariables;
21
+ /** Simulator config for the processor's PublicTxSimulator. */
22
+ config?: Partial<PublicSimulatorConfig>;
23
+ }
24
+
25
+ function defaultGlobals(): GlobalVariables {
26
+ const globals = GlobalVariables.empty();
27
+ globals.gasFees = new GasFees(2, 3);
28
+ return globals;
29
+ }
30
+
31
+ const defaultConfig = PublicSimulatorConfig.from({
32
+ skipFeeEnforcement: false,
33
+ collectDebugLogs: true,
34
+ collectHints: false,
35
+ collectStatistics: false,
36
+ collectCallMetadata: true,
37
+ });
38
+
39
+ /**
40
+ * Bundles the real-AVM wiring shared by public-processor app tests: a live WSDB world state, a CDB IPC
41
+ * server, a spawned AVM simulator, a {@link PublicProcessor} backed by all three, and a setup-only
42
+ * {@link PublicTxSimulationTester} sharing the same fork and contract data source for building txs and
43
+ * seeding balances. Own it with `await using`, or call {@link Symbol.asyncDispose} from `afterEach`.
44
+ */
45
+ export class PublicProcessorTestEnv implements AsyncDisposable {
46
+ private constructor(
47
+ public readonly processor: PublicProcessor,
48
+ public readonly tester: PublicTxSimulationTester,
49
+ public readonly contractsDB: PublicContractsDB,
50
+ public readonly globals: GlobalVariables,
51
+ private readonly worldStateService: NativeWorldStateService,
52
+ private readonly avmSimulator: AvmSimulatorPool,
53
+ ) {}
54
+
55
+ static async create(opts: PublicProcessorTestEnvOptions = {}): Promise<PublicProcessorTestEnv> {
56
+ const globals = opts.globals ?? defaultGlobals();
57
+ const config = opts.config ? PublicSimulatorConfig.from({ ...defaultConfig, ...opts.config }) : defaultConfig;
58
+
59
+ const contractDataSource = new SimpleContractDataSource();
60
+ const worldStateService = await NativeWorldStateService.tmp();
61
+ const merkleTrees = await worldStateService.fork();
62
+ const contractsDB = new PublicContractsDB(contractDataSource);
63
+
64
+ const forkId = merkleTrees.getRevision().forkId;
65
+ const avmSimulator = await AvmSimulatorPool.spawn({ wsdbIpcPath: worldStateService.getIpcPath() });
66
+
67
+ const simulator = new PublicTxSimulator(avmSimulator, globals, contractsDB, forkId, config, undefined);
68
+ const processor = new PublicProcessor(
69
+ globals,
70
+ new GuardedMerkleTreeOperations(merkleTrees),
71
+ contractsDB,
72
+ simulator,
73
+ new TestDateProvider(),
74
+ getTelemetryClient(),
75
+ createLogger('simulator:public-processor'),
76
+ );
77
+
78
+ const tester = new PublicTxSimulationTester(merkleTrees, contractDataSource, globals);
79
+
80
+ return new PublicProcessorTestEnv(processor, tester, contractsDB, globals, worldStateService, avmSimulator);
81
+ }
82
+
83
+ async [Symbol.asyncDispose](): Promise<void> {
84
+ await this.avmSimulator[Symbol.asyncDispose]();
85
+ await this.tester.close();
86
+ await this.worldStateService.close();
87
+ }
88
+ }
@@ -0,0 +1,315 @@
1
+ import { PUBLIC_TX_L2_GAS_OVERHEAD, TX_DA_GAS_OVERHEAD } from '@aztec-labs/constants';
2
+ import { asyncMap } from '@aztec-labs/foundation/async-map';
3
+ import { BlockNumber } from '@aztec-labs/foundation/branded-types';
4
+ import { Fr } from '@aztec-labs/foundation/curves/bn254';
5
+ import { type ContractArtifact, encodeArguments } from '@aztec-labs/stdlib/abi';
6
+ import { PublicSimulatorConfig, type PublicTxResult } from '@aztec-labs/stdlib/avm';
7
+ import type { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
8
+ import { Gas, GasFees } from '@aztec-labs/stdlib/gas';
9
+ import type { MerkleTreeWriteOperations } from '@aztec-labs/stdlib/interfaces/server';
10
+ import { PublicCallRequest } from '@aztec-labs/stdlib/kernel';
11
+ import { GlobalVariables, PublicCallRequestWithCalldata, type Tx } from '@aztec-labs/stdlib/tx';
12
+ import { NativeWorldStateService } from '@aztec-labs/world-state';
13
+
14
+ import { BaseAvmSimulationTester } from '../avm/testing/base_avm_simulation_tester.js';
15
+ import {
16
+ DEFAULT_BLOCK_NUMBER,
17
+ DEFAULT_TIMESTAMP,
18
+ getContractFunctionAbi,
19
+ getFunctionSelector,
20
+ } from '../avm/testing/utils.js';
21
+ import { AvmSimulatorPool } from '../avm_simulator_pool.js';
22
+ import { PublicContractsDB } from '../public_db_sources.js';
23
+ import { MeasuredPublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
24
+ import type { MeasuredPublicTxSimulatorInterface } from '../public_tx_simulator/public_tx_simulator_interface.js';
25
+ import { TestExecutorMetrics } from '../test_executor_metrics.js';
26
+ import { SimpleContractDataSource } from './simple_contract_data_source.js';
27
+ import { type TestPrivateInsertions, createTxForPublicCalls } from './utils.js';
28
+
29
+ const DEFAULT_GAS_FEES = new GasFees(2, 3);
30
+ const TEARDOWN_DA_GAS_LIMIT = 98_304;
31
+ const TEARDOWN_L2_GAS_LIMIT = 817_500;
32
+
33
+ export type TestEnqueuedCall = {
34
+ sender?: AztecAddress;
35
+ address: AztecAddress;
36
+ fnName?: string;
37
+ args: any[];
38
+ isStaticCall?: boolean;
39
+ contractArtifact?: ContractArtifact;
40
+ };
41
+
42
+ const defaultConfig: PublicSimulatorConfig = PublicSimulatorConfig.from({
43
+ skipFeeEnforcement: false,
44
+ collectCallMetadata: true,
45
+ collectDebugLogs: true,
46
+ collectHints: false,
47
+ collectPublicInputs: false,
48
+ collectStatistics: false,
49
+ });
50
+
51
+ /**
52
+ * Factory type for creating a MeasuredPublicTxSimulatorInterface.
53
+ */
54
+ export type MeasuredSimulatorFactory = (
55
+ merkleTree: MerkleTreeWriteOperations,
56
+ contractsDB: PublicContractsDB,
57
+ globals: GlobalVariables,
58
+ metrics: TestExecutorMetrics,
59
+ config: PublicSimulatorConfig,
60
+ ) => MeasuredPublicTxSimulatorInterface;
61
+
62
+ /**
63
+ * A test class that extends the BaseAvmSimulationTester to enable real-app testing of the PublicTxSimulator.
64
+ * It provides an interface for simulating one transaction at a time and maintains state between subsequent
65
+ * transactions.
66
+ */
67
+ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
68
+ protected txCount: number = 0;
69
+ private simulator: MeasuredPublicTxSimulatorInterface | undefined;
70
+ private metricsPrefix?: string;
71
+ protected avmSimulator?: AvmSimulatorPool;
72
+
73
+ constructor(
74
+ merkleTree: MerkleTreeWriteOperations,
75
+ contractDataSource: SimpleContractDataSource,
76
+ globals: GlobalVariables = defaultGlobals(),
77
+ private metrics: TestExecutorMetrics = new TestExecutorMetrics(),
78
+ simulatorFactory?: MeasuredSimulatorFactory,
79
+ config: PublicSimulatorConfig = defaultConfig,
80
+ ) {
81
+ super(contractDataSource, merkleTree);
82
+
83
+ const contractsDB = new PublicContractsDB(contractDataSource);
84
+ if (simulatorFactory) {
85
+ this.simulator = simulatorFactory(merkleTree, contractsDB, globals, this.metrics, config);
86
+ } else {
87
+ // No simulator — this tester can only be used for setup (setFeePayerBalance, createTx, etc.)
88
+ // To simulate, use PublicTxSimulationTester.create() or pass a simulatorFactory.
89
+ this.simulator = undefined;
90
+ }
91
+ }
92
+
93
+ public static async create(
94
+ worldStateService: NativeWorldStateService, // make sure to close this later
95
+ globals: GlobalVariables = defaultGlobals(),
96
+ metrics: TestExecutorMetrics = new TestExecutorMetrics(),
97
+ config: PublicSimulatorConfig = defaultConfig,
98
+ ): Promise<PublicTxSimulationTester> {
99
+ const contractDataSource = new SimpleContractDataSource();
100
+ const merkleTree = await worldStateService.fork();
101
+
102
+ const avmSimulator = await AvmSimulatorPool.spawn({ wsdbIpcPath: worldStateService.getIpcPath() });
103
+ const simulatorFactory: MeasuredSimulatorFactory = (mt, cdb, g, m, c) =>
104
+ new MeasuredPublicTxSimulator(avmSimulator, g, cdb, mt.getRevision().forkId, m, c, undefined);
105
+
106
+ const tester = new PublicTxSimulationTester(
107
+ merkleTree,
108
+ contractDataSource,
109
+ globals,
110
+ metrics,
111
+ simulatorFactory,
112
+ config,
113
+ );
114
+ tester.avmSimulator = avmSimulator;
115
+ return tester;
116
+ }
117
+
118
+ public setMetricsPrefix(prefix: string) {
119
+ this.metricsPrefix = prefix;
120
+ }
121
+
122
+ public async createTx(
123
+ sender: AztecAddress,
124
+ setupCalls: TestEnqueuedCall[] = [],
125
+ appCalls: TestEnqueuedCall[] = [],
126
+ teardownCall?: TestEnqueuedCall,
127
+ feePayer: AztecAddress = sender,
128
+ /* need some unique first nullifier for note-nonce computations */
129
+ privateInsertions: TestPrivateInsertions = { nonRevertible: { nullifiers: [new Fr(420000 + this.txCount)] } },
130
+ gasLimits?: Gas,
131
+ ): Promise<Tx> {
132
+ const setupCallRequests = await asyncMap(setupCalls, call =>
133
+ this.#createPubicCallRequestForCall(call, call.sender ?? sender),
134
+ );
135
+ const appCallRequests = await asyncMap(appCalls, call =>
136
+ this.#createPubicCallRequestForCall(call, call.sender ?? sender),
137
+ );
138
+ const teardownCallRequest = teardownCall
139
+ ? await this.#createPubicCallRequestForCall(teardownCall, teardownCall.sender ?? sender)
140
+ : undefined;
141
+
142
+ this.txCount++;
143
+ return createTxForPublicCalls(
144
+ privateInsertions,
145
+ setupCallRequests,
146
+ appCallRequests,
147
+ teardownCallRequest,
148
+ feePayer,
149
+ /*gasUsedByPrivate*/ teardownCall
150
+ ? new Gas(TEARDOWN_DA_GAS_LIMIT + TX_DA_GAS_OVERHEAD, TEARDOWN_L2_GAS_LIMIT + PUBLIC_TX_L2_GAS_OVERHEAD)
151
+ : new Gas(TX_DA_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD),
152
+ defaultGlobals(),
153
+ gasLimits,
154
+ );
155
+ }
156
+
157
+ public async simulateTx(
158
+ sender: AztecAddress,
159
+ setupCalls: TestEnqueuedCall[] = [],
160
+ appCalls: TestEnqueuedCall[] = [],
161
+ teardownCall?: TestEnqueuedCall,
162
+ feePayer: AztecAddress = sender,
163
+ /* need some unique first nullifier for note-nonce computations */
164
+ privateInsertions?: TestPrivateInsertions,
165
+ txLabel: string = 'unlabeledTx',
166
+ gasLimits?: Gas,
167
+ ): Promise<PublicTxResult> {
168
+ const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions, gasLimits);
169
+
170
+ await this.setFeePayerBalance(feePayer);
171
+
172
+ const txLabelWithCount = `${txLabel}/${this.txCount - 1}`;
173
+ const fullTxLabel = this.metricsPrefix ? `${this.metricsPrefix}/${txLabelWithCount}` : txLabelWithCount;
174
+
175
+ if (!this.simulator) {
176
+ throw new Error(
177
+ 'No simulator configured. Pass a simulatorFactory to the constructor or use PublicTxSimulationTester.create()',
178
+ );
179
+ }
180
+ const avmResult = await this.simulator.simulate(tx, fullTxLabel);
181
+
182
+ // Something like this is often useful for debugging:
183
+ //if (avmResult.revertReason) {
184
+ // // resolve / enrich revert reason
185
+ // const lastAppCall = appCalls[appCalls.length - 1];
186
+
187
+ // const contractArtifact =
188
+ // lastAppCall.contractArtifact || (await this.contractDataSource.getContractArtifact(lastAppCall.address));
189
+ // const fnAbi = getContractFunctionAbi(lastAppCall.fnName, contractArtifact!);
190
+ // const revertReason = resolveAssertionMessageFromRevertData(avmResult.revertReason.revertData, fnAbi!);
191
+ // this.logger.debug(`Revert reason: ${revertReason}`);
192
+ //}
193
+
194
+ return avmResult;
195
+ }
196
+
197
+ /**
198
+ * Just simulate the transaction and return the result.
199
+ *
200
+ * This wrapper around simulation allows for easy labeling of a TX
201
+ * which is especially useful when reporting benchmarks or metrics.
202
+ */
203
+ public async simulateTxWithLabel(
204
+ txLabel: string,
205
+ sender: AztecAddress,
206
+ setupCalls?: TestEnqueuedCall[],
207
+ appCalls?: TestEnqueuedCall[],
208
+ teardownCall?: TestEnqueuedCall,
209
+ feePayer?: AztecAddress,
210
+ privateInsertions?: TestPrivateInsertions,
211
+ ): Promise<PublicTxResult> {
212
+ return await this.simulateTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions, txLabel);
213
+ }
214
+
215
+ /**
216
+ * Execute a transaction and return the result.
217
+ *
218
+ * This function can be (it is) overridden by a subclass (AvmProvingTester)
219
+ * to do more work (like prove and verify) while still reusing existing
220
+ * test fixtures (like amm_test). That is why it is not named "simulate*".
221
+ */
222
+ public async executeTxWithLabel(
223
+ txLabel: string,
224
+ sender: AztecAddress,
225
+ setupCalls?: TestEnqueuedCall[],
226
+ appCalls?: TestEnqueuedCall[],
227
+ teardownCall?: TestEnqueuedCall,
228
+ feePayer?: AztecAddress,
229
+ privateInsertions?: TestPrivateInsertions,
230
+ ): Promise<PublicTxResult> {
231
+ return await this.simulateTxWithLabel(
232
+ txLabel,
233
+ sender,
234
+ setupCalls,
235
+ appCalls,
236
+ teardownCall,
237
+ feePayer,
238
+ privateInsertions,
239
+ );
240
+ }
241
+
242
+ public prettyPrintMetrics() {
243
+ this.metrics.prettyPrint();
244
+ }
245
+
246
+ /** Clean up IPC resources (AVM simulator pool and merkle tree fork) created by create(). */
247
+ public async close(): Promise<void> {
248
+ await this.avmSimulator?.[Symbol.asyncDispose]();
249
+ // Close the merkle tree fork to release IPC resources before the wsdb process is killed.
250
+ if (this.merkleTrees?.close) {
251
+ await this.merkleTrees.close().catch(() => {});
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Cancel the current simulation if one is in progress.
257
+ * This signals the underlying simulator to stop at the next safe point.
258
+ * Safe to call even if no simulation is in progress.
259
+ *
260
+ * @param waitTimeoutMs - If provided, wait up to this many ms for the simulation to actually stop.
261
+ */
262
+ public async cancel(waitTimeoutMs?: number): Promise<void> {
263
+ await this.simulator?.cancel?.(waitTimeoutMs);
264
+ }
265
+
266
+ /**
267
+ * Get the underlying simulator for advanced test scenarios.
268
+ * Use this when you need direct control over simulation (e.g., for testing cancellation).
269
+ */
270
+ public getSimulator(): MeasuredPublicTxSimulatorInterface | undefined {
271
+ return this.simulator;
272
+ }
273
+
274
+ async #createPubicCallRequestForCall(
275
+ call: TestEnqueuedCall,
276
+ sender: AztecAddress,
277
+ ): Promise<PublicCallRequestWithCalldata> {
278
+ const address = call.address;
279
+ const contractArtifact = call.contractArtifact || (await this.contractDataSource.getContractArtifact(address));
280
+ if (!contractArtifact) {
281
+ throw new Error(`Contract artifact not found for address: ${address}`);
282
+ }
283
+
284
+ let calldata: Fr[] = [];
285
+ if (!call.fnName) {
286
+ this.logger.debug(
287
+ `No function name specified for call to contract ${call.address.toString()}. Assuming this is a custom bytecode with no public_dispatch function.`,
288
+ );
289
+ this.logger.debug(`Not using ABI to encode arguments. Not prepending fn selector to calldata.`);
290
+ try {
291
+ calldata = call.args.map(arg => new Fr(arg));
292
+ } catch (error) {
293
+ this.logger.warn(`Tried assuming that all arguments are Field-like. Failed. Error: ${error}`);
294
+ throw error;
295
+ }
296
+ } else {
297
+ const fnSelector = await getFunctionSelector(call.fnName, contractArtifact);
298
+ const fnAbi = getContractFunctionAbi(call.fnName, contractArtifact)!;
299
+ const encodedArgs = encodeArguments(fnAbi, call.args);
300
+ calldata = [fnSelector.toField(), ...encodedArgs];
301
+ }
302
+ const isStaticCall = call.isStaticCall ?? false;
303
+ const request = await PublicCallRequest.fromCalldata(sender, address, isStaticCall, calldata);
304
+
305
+ return new PublicCallRequestWithCalldata(request, calldata);
306
+ }
307
+ }
308
+
309
+ export function defaultGlobals() {
310
+ const globals = GlobalVariables.empty();
311
+ globals.timestamp = DEFAULT_TIMESTAMP;
312
+ globals.gasFees = DEFAULT_GAS_FEES; // apply some nonzero default gas fees
313
+ globals.blockNumber = BlockNumber(DEFAULT_BLOCK_NUMBER);
314
+ return globals;
315
+ }
@@ -0,0 +1,122 @@
1
+ import type { BlockNumber } from '@aztec-labs/foundation/branded-types';
2
+ import { Fr } from '@aztec-labs/foundation/curves/bn254';
3
+ import { createLogger } from '@aztec-labs/foundation/log';
4
+ import type { ContractArtifact, FunctionSelector } from '@aztec-labs/stdlib/abi';
5
+ import type { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
6
+ import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec-labs/stdlib/contract';
7
+
8
+ import { getFunctionSelector } from '../avm/testing/utils.js';
9
+
10
+ /**
11
+ * This class is used during public/avm testing to function as a database of
12
+ * contract contract classes and instances. Tests can populate it with classes
13
+ * and instances and then probe it via the ContractDataSource interface.
14
+ *
15
+ * This class does not include any real merkle trees & merkle operations.
16
+ */
17
+ export class SimpleContractDataSource implements ContractDataSource {
18
+ public logger = createLogger('simple-contract-data-source');
19
+
20
+ // maps contract class ID to class
21
+ private contractClasses: Map<string, ContractClassPublic> = new Map();
22
+ // maps contract instance address to instance
23
+ private contractInstances: Map<string, ContractInstanceWithAddress> = new Map();
24
+ // maps contract instance address to address
25
+ private contractArtifacts: Map<string, ContractArtifact> = new Map();
26
+ // maps `${classID}:${fnSelector}` to name
27
+ private debugFunctionName: Map<string, string> = new Map();
28
+
29
+ /////////////////////////////////////////////////////////////
30
+ // Helper functions not in the contract data source interface
31
+ /**
32
+ * Derive the contract class and instance with some seed.
33
+ * Add both to the contract data source along with the contract artifact.
34
+ */
35
+ async addNewContract(
36
+ contractArtifact: ContractArtifact,
37
+ contractClass: ContractClassPublic,
38
+ contractInstance: ContractInstanceWithAddress,
39
+ ) {
40
+ await this.addContractArtifact(contractClass.id, contractArtifact);
41
+ await this.addContractClass(contractClass);
42
+ await this.addContractInstance(contractInstance);
43
+ }
44
+
45
+ async addContractArtifact(classId: Fr, artifact: ContractArtifact) {
46
+ this.contractArtifacts.set(classId.toString(), artifact);
47
+ const classIdStr = classId.toString();
48
+ const publicFns = artifact.nonDispatchPublicFunctions;
49
+ if (publicFns.length !== 0) {
50
+ for (const fn of publicFns) {
51
+ const actualFnName = `${fn.name}`;
52
+ const fnSelector = await getFunctionSelector(actualFnName, artifact);
53
+ const key = `${classIdStr}:${fnSelector.toString()}`;
54
+
55
+ const longFnName = `${artifact.name}.${actualFnName}`;
56
+ this.debugFunctionName.set(key, longFnName);
57
+ }
58
+ }
59
+ }
60
+
61
+ /////////////////////////////////////////////////////////////
62
+ // ContractDataSource function implementations
63
+ getBlockNumber(): Promise<BlockNumber> {
64
+ throw new Error('Method not implemented.');
65
+ }
66
+
67
+ getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
68
+ return Promise.resolve(this.contractClasses.get(id.toString()));
69
+ }
70
+
71
+ getBytecodeCommitment(_id: Fr): Promise<Fr | undefined> {
72
+ return Promise.resolve(undefined);
73
+ }
74
+
75
+ getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
76
+ return Promise.resolve(this.contractInstances.get(address.toString()));
77
+ }
78
+
79
+ getContractClassIds(): Promise<Fr[]> {
80
+ throw new Error('Method not implemented.');
81
+ }
82
+
83
+ async getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
84
+ const contractInstance = await this.getContract(address);
85
+ if (!contractInstance) {
86
+ this.logger.warn(`Contract not found at address: ${address}`);
87
+ return undefined;
88
+ }
89
+ this.logger.debug(`Retrieved contract artifact for address: ${address}`);
90
+ this.logger.debug(`Contract class ID: ${contractInstance.currentContractClassId}`);
91
+ return this.contractArtifacts.get(contractInstance!.currentContractClassId.toString());
92
+ }
93
+
94
+ async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
95
+ const contractInstance = await this.getContract(address);
96
+ if (!contractInstance) {
97
+ this.logger.warn(`Couldn't get fn name for debugging. Contract not in tester's ContractDataSource.`);
98
+ return undefined;
99
+ }
100
+ const key = `${contractInstance.currentContractClassId.toString()}:${selector.toString()}`;
101
+ const fnName = this.debugFunctionName.get(key);
102
+ if (!fnName) {
103
+ this.logger.warn(`Couldn't get fn name for debugging...`);
104
+ return undefined;
105
+ }
106
+ return fnName;
107
+ }
108
+
109
+ registerContractFunctionSignatures(_signatures: string[]): Promise<void> {
110
+ return Promise.resolve();
111
+ }
112
+
113
+ addContractClass(contractClass: ContractClassPublic): Promise<void> {
114
+ this.contractClasses.set(contractClass.id.toString(), contractClass);
115
+ return Promise.resolve();
116
+ }
117
+
118
+ addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
119
+ this.contractInstances.set(contractInstance.address.toString(), contractInstance);
120
+ return Promise.resolve();
121
+ }
122
+ }