@aztec/simulator 2.1.0-rc.9 → 3.0.0-devnet.2

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 (161) hide show
  1. package/dest/private/acvm_native.d.ts +1 -2
  2. package/dest/private/acvm_native.d.ts.map +1 -1
  3. package/dest/private/circuit_recording/simulator_recorder_wrapper.d.ts +1 -1
  4. package/dest/private/circuit_recording/simulator_recorder_wrapper.d.ts.map +1 -1
  5. package/dest/public/avm/avm_execution_environment.d.ts +2 -1
  6. package/dest/public/avm/avm_execution_environment.d.ts.map +1 -1
  7. package/dest/public/avm/avm_execution_environment.js +5 -2
  8. package/dest/public/avm/avm_gas.js +2 -2
  9. package/dest/public/avm/avm_simulator.d.ts +1 -1
  10. package/dest/public/avm/avm_simulator.d.ts.map +1 -1
  11. package/dest/public/avm/avm_simulator.js +14 -21
  12. package/dest/public/avm/errors.d.ts +5 -14
  13. package/dest/public/avm/errors.d.ts.map +1 -1
  14. package/dest/public/avm/errors.js +7 -20
  15. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts +2 -1
  16. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
  17. package/dest/public/avm/fixtures/avm_simulation_tester.js +2 -3
  18. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +2 -0
  19. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
  20. package/dest/public/avm/fixtures/base_avm_simulation_tester.js +22 -0
  21. package/dest/public/avm/fixtures/initializers.d.ts.map +1 -1
  22. package/dest/public/avm/fixtures/initializers.js +2 -2
  23. package/dest/public/avm/opcodes/accrued_substate.d.ts +2 -2
  24. package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
  25. package/dest/public/avm/opcodes/accrued_substate.js +7 -7
  26. package/dest/public/avm/opcodes/addressing_mode.d.ts.map +1 -1
  27. package/dest/public/avm/opcodes/addressing_mode.js +2 -3
  28. package/dest/public/avm/opcodes/conversion.d.ts.map +1 -1
  29. package/dest/public/avm/opcodes/conversion.js +3 -0
  30. package/dest/public/avm/opcodes/ec_add.d.ts.map +1 -1
  31. package/dest/public/avm/opcodes/ec_add.js +3 -2
  32. package/dest/public/avm/opcodes/environment_getters.d.ts.map +1 -1
  33. package/dest/public/avm/opcodes/environment_getters.js +5 -7
  34. package/dest/public/avm/opcodes/instruction.d.ts.map +1 -1
  35. package/dest/public/avm/opcodes/instruction.js +5 -6
  36. package/dest/public/avm/opcodes/misc.d.ts +2 -1
  37. package/dest/public/avm/opcodes/misc.d.ts.map +1 -1
  38. package/dest/public/avm/opcodes/misc.js +28 -8
  39. package/dest/public/avm/serialization/instruction_serialization.d.ts +8 -0
  40. package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
  41. package/dest/public/avm/serialization/instruction_serialization.js +10 -0
  42. package/dest/public/avm/test_utils.d.ts +2 -2
  43. package/dest/public/avm/test_utils.d.ts.map +1 -1
  44. package/dest/public/avm/test_utils.js +6 -9
  45. package/dest/public/fixtures/bulk_test.d.ts.map +1 -1
  46. package/dest/public/fixtures/bulk_test.js +63 -130
  47. package/dest/public/fixtures/custom_bytecode_tester.d.ts +12 -0
  48. package/dest/public/fixtures/custom_bytecode_tester.d.ts.map +1 -0
  49. package/dest/public/fixtures/custom_bytecode_tester.js +29 -0
  50. package/dest/public/fixtures/custom_bytecode_tests.d.ts +9 -0
  51. package/dest/public/fixtures/custom_bytecode_tests.d.ts.map +1 -0
  52. package/dest/public/fixtures/custom_bytecode_tests.js +109 -0
  53. package/dest/public/fixtures/index.d.ts +2 -1
  54. package/dest/public/fixtures/index.d.ts.map +1 -1
  55. package/dest/public/fixtures/index.js +2 -1
  56. package/dest/public/fixtures/minimal_public_tx.d.ts +2 -1
  57. package/dest/public/fixtures/minimal_public_tx.d.ts.map +1 -1
  58. package/dest/public/fixtures/minimal_public_tx.js +8 -22
  59. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +4 -2
  60. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  61. package/dest/public/fixtures/public_tx_simulation_tester.js +11 -6
  62. package/dest/public/fixtures/utils.js +1 -1
  63. package/dest/public/hinting_db_sources.d.ts +2 -0
  64. package/dest/public/hinting_db_sources.d.ts.map +1 -1
  65. package/dest/public/hinting_db_sources.js +3 -0
  66. package/dest/public/index.d.ts +1 -1
  67. package/dest/public/index.d.ts.map +1 -1
  68. package/dest/public/public_db_sources.d.ts +2 -2
  69. package/dest/public/public_db_sources.d.ts.map +1 -1
  70. package/dest/public/public_db_sources.js +11 -1
  71. package/dest/public/public_errors.d.ts +12 -0
  72. package/dest/public/public_errors.d.ts.map +1 -0
  73. package/dest/public/public_errors.js +13 -0
  74. package/dest/public/public_processor/guarded_merkle_tree.d.ts +2 -0
  75. package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
  76. package/dest/public/public_processor/guarded_merkle_tree.js +3 -0
  77. package/dest/public/public_processor/public_processor.d.ts +9 -4
  78. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  79. package/dest/public/public_processor/public_processor.js +12 -6
  80. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts +41 -0
  81. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts.map +1 -0
  82. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.js +89 -0
  83. package/dest/public/public_tx_simulator/index.d.ts +1 -0
  84. package/dest/public/public_tx_simulator/index.d.ts.map +1 -1
  85. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +5 -4
  86. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -1
  87. package/dest/public/public_tx_simulator/measured_public_tx_simulator.js +3 -4
  88. package/dest/public/public_tx_simulator/public_tx_context.d.ts +4 -2
  89. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  90. package/dest/public/public_tx_simulator/public_tx_context.js +12 -8
  91. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +24 -11
  92. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  93. package/dest/public/public_tx_simulator/public_tx_simulator.js +112 -44
  94. package/dest/public/public_tx_simulator/public_tx_simulator_interface.d.ts +9 -0
  95. package/dest/public/public_tx_simulator/public_tx_simulator_interface.d.ts.map +1 -0
  96. package/dest/public/public_tx_simulator/public_tx_simulator_interface.js +1 -0
  97. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts +2 -1
  98. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts.map +1 -1
  99. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.js +2 -2
  100. package/dest/public/side_effect_errors.d.ts +41 -1
  101. package/dest/public/side_effect_errors.d.ts.map +1 -1
  102. package/dest/public/side_effect_errors.js +70 -1
  103. package/dest/public/side_effect_trace.d.ts +11 -4
  104. package/dest/public/side_effect_trace.d.ts.map +1 -1
  105. package/dest/public/side_effect_trace.js +35 -20
  106. package/dest/public/side_effect_trace_interface.d.ts +6 -0
  107. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  108. package/dest/public/state_manager/nullifiers.d.ts +0 -3
  109. package/dest/public/state_manager/nullifiers.d.ts.map +1 -1
  110. package/dest/public/state_manager/nullifiers.js +1 -6
  111. package/dest/public/state_manager/state_manager.d.ts +7 -2
  112. package/dest/public/state_manager/state_manager.d.ts.map +1 -1
  113. package/dest/public/state_manager/state_manager.js +54 -15
  114. package/package.json +21 -17
  115. package/src/private/acvm_native.ts +1 -2
  116. package/src/private/circuit_recording/simulator_recorder_wrapper.ts +1 -1
  117. package/src/public/avm/avm_execution_environment.ts +4 -1
  118. package/src/public/avm/avm_gas.ts +2 -2
  119. package/src/public/avm/avm_simulator.ts +16 -27
  120. package/src/public/avm/errors.ts +7 -24
  121. package/src/public/avm/fixtures/avm_simulation_tester.ts +4 -2
  122. package/src/public/avm/fixtures/base_avm_simulation_tester.ts +32 -0
  123. package/src/public/avm/fixtures/initializers.ts +2 -1
  124. package/src/public/avm/opcodes/accrued_substate.ts +4 -4
  125. package/src/public/avm/opcodes/addressing_mode.ts +3 -3
  126. package/src/public/avm/opcodes/conversion.ts +4 -0
  127. package/src/public/avm/opcodes/ec_add.ts +3 -2
  128. package/src/public/avm/opcodes/environment_getters.ts +6 -8
  129. package/src/public/avm/opcodes/instruction.ts +8 -6
  130. package/src/public/avm/opcodes/misc.ts +41 -7
  131. package/src/public/avm/serialization/instruction_serialization.ts +12 -0
  132. package/src/public/avm/test_utils.ts +6 -14
  133. package/src/public/fixtures/bulk_test.ts +41 -23
  134. package/src/public/fixtures/custom_bytecode_tester.ts +49 -0
  135. package/src/public/fixtures/custom_bytecode_tests.ts +135 -0
  136. package/src/public/fixtures/index.ts +2 -1
  137. package/src/public/fixtures/minimal_public_tx.ts +8 -31
  138. package/src/public/fixtures/public_tx_simulation_tester.ts +16 -12
  139. package/src/public/fixtures/utils.ts +1 -1
  140. package/src/public/hinting_db_sources.ts +5 -0
  141. package/src/public/index.ts +6 -1
  142. package/src/public/public_db_sources.ts +19 -3
  143. package/src/public/public_errors.ts +14 -0
  144. package/src/public/public_processor/guarded_merkle_tree.ts +4 -0
  145. package/src/public/public_processor/public_processor.ts +23 -25
  146. package/src/public/public_tx_simulator/cpp_public_tx_simulator.ts +128 -0
  147. package/src/public/public_tx_simulator/index.ts +1 -0
  148. package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +12 -9
  149. package/src/public/public_tx_simulator/public_tx_context.ts +11 -4
  150. package/src/public/public_tx_simulator/public_tx_simulator.ts +178 -60
  151. package/src/public/public_tx_simulator/public_tx_simulator_interface.ts +11 -0
  152. package/src/public/public_tx_simulator/telemetry_public_tx_simulator.ts +3 -12
  153. package/src/public/side_effect_errors.ts +91 -1
  154. package/src/public/side_effect_trace.ts +48 -23
  155. package/src/public/side_effect_trace_interface.ts +6 -0
  156. package/src/public/state_manager/nullifiers.ts +1 -7
  157. package/src/public/state_manager/state_manager.ts +73 -25
  158. package/dest/public/bytecode_errors.d.ts +0 -4
  159. package/dest/public/bytecode_errors.d.ts.map +0 -1
  160. package/dest/public/bytecode_errors.js +0 -6
  161. package/src/public/bytecode_errors.ts +0 -6
@@ -3,7 +3,6 @@ import {
3
3
  MAX_L2_TO_L1_MSGS_PER_TX,
4
4
  MAX_NOTE_HASHES_PER_TX,
5
5
  MAX_NULLIFIERS_PER_TX,
6
- MAX_PUBLIC_LOGS_PER_TX,
7
6
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
8
7
  } from '@aztec/constants';
9
8
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -28,11 +27,12 @@ import {
28
27
  PublicCallRequestArrayLengths,
29
28
  countAccumulatedItems,
30
29
  } from '@aztec/stdlib/kernel';
31
- import { PublicLog } from '@aztec/stdlib/logs';
30
+ import { FlatPublicLogs } from '@aztec/stdlib/logs';
32
31
  import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
33
32
  import { MerkleTreeId } from '@aztec/stdlib/trees';
34
33
  import {
35
34
  type GlobalVariables,
35
+ ProtocolContracts,
36
36
  PublicCallRequestWithCalldata,
37
37
  TreeSnapshots,
38
38
  type Tx,
@@ -71,6 +71,8 @@ export class PublicTxContext {
71
71
  public readonly state: PhaseStateManager,
72
72
  private readonly startTreeSnapshots: TreeSnapshots,
73
73
  private readonly globalVariables: GlobalVariables,
74
+ private readonly protocolContracts: ProtocolContracts,
75
+ private readonly proverId: Fr,
74
76
  private readonly gasSettings: GasSettings,
75
77
  private readonly gasUsedByPrivate: Gas,
76
78
  private readonly gasAllocatedToPublic: Gas,
@@ -91,7 +93,9 @@ export class PublicTxContext {
91
93
  contractsDB: PublicContractsDBInterface,
92
94
  tx: Tx,
93
95
  globalVariables: GlobalVariables,
96
+ protocolContracts: ProtocolContracts,
94
97
  doMerkleOperations: boolean,
98
+ proverId: Fr,
95
99
  ) {
96
100
  const nonRevertibleAccumulatedDataFromPrivate = tx.data.forPublic!.nonRevertibleAccumulatedData;
97
101
 
@@ -119,6 +123,8 @@ export class PublicTxContext {
119
123
  new PhaseStateManager(txStateManager),
120
124
  await txStateManager.getTreeSnapshots(),
121
125
  globalVariables,
126
+ protocolContracts,
127
+ proverId,
122
128
  gasSettings,
123
129
  gasUsedByPrivate,
124
130
  gasAllocatedToPublic,
@@ -331,7 +337,6 @@ export class PublicTxContext {
331
337
  avmNoteHashes.length,
332
338
  avmNullifiers.length,
333
339
  avmL2ToL1Msgs.length,
334
- finalPublicLogs.length,
335
340
  finalPublicDataWrites.length,
336
341
  );
337
342
 
@@ -347,7 +352,7 @@ export class PublicTxContext {
347
352
  MAX_NULLIFIERS_PER_TX,
348
353
  ),
349
354
  /*l2ToL1Msgs=*/ padArrayEnd(avmL2ToL1Msgs, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
350
- /*publicLogs=*/ padArrayEnd(finalPublicLogs, PublicLog.empty(), MAX_PUBLIC_LOGS_PER_TX),
355
+ /*publicLogs=*/ FlatPublicLogs.fromLogs(finalPublicLogs),
351
356
  /*publicDataWrites=*/ padArrayEnd(
352
357
  finalPublicDataWrites,
353
358
  PublicDataWrite.empty(),
@@ -376,11 +381,13 @@ export class PublicTxContext {
376
381
 
377
382
  return new AvmCircuitPublicInputs(
378
383
  this.globalVariables,
384
+ this.protocolContracts,
379
385
  this.startTreeSnapshots,
380
386
  /*startGasUsed=*/ this.gasUsedByPrivate,
381
387
  this.gasSettings,
382
388
  computeEffectiveGasFees(this.globalVariables.gasFees, this.gasSettings),
383
389
  this.feePayer,
390
+ this.proverId,
384
391
  /*publicCallRequestArrayLengths=*/ new PublicCallRequestArrayLengths(
385
392
  this.setupCallRequests.length,
386
393
  this.appLogicCallRequests.length,
@@ -1,7 +1,7 @@
1
- import { AVM_MAX_PROCESSABLE_L2_GAS } from '@aztec/constants';
2
- import type { Fr } from '@aztec/foundation/fields';
1
+ import { AVM_MAX_PROCESSABLE_L2_GAS, DEFAULT_MAX_DEBUG_LOG_MEMORY_READS } from '@aztec/constants';
2
+ import { Fr } from '@aztec/foundation/fields';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
- import { ProtocolContractAddress } from '@aztec/protocol-contracts';
4
+ import { ProtocolContractAddress, ProtocolContractsList } from '@aztec/protocol-contracts';
5
5
  import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
6
6
  import {
7
7
  AvmCircuitInputs,
@@ -13,6 +13,7 @@ import {
13
13
  } from '@aztec/stdlib/avm';
14
14
  import { SimulationError } from '@aztec/stdlib/errors';
15
15
  import type { Gas, GasUsed } from '@aztec/stdlib/gas';
16
+ import type { DebugLog } from '@aztec/stdlib/logs';
16
17
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
17
18
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
18
19
  import {
@@ -23,13 +24,22 @@ import {
23
24
  TxExecutionPhase,
24
25
  } from '@aztec/stdlib/tx';
25
26
 
27
+ import { strict as assert } from 'assert';
28
+
26
29
  import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
27
30
  import { AvmSimulator } from '../avm/index.js';
28
31
  import { getPublicFunctionDebugName } from '../debug_fn_name.js';
29
32
  import { HintingMerkleWriteOperations, HintingPublicContractsDB } from '../hinting_db_sources.js';
30
33
  import { type PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
34
+ import {
35
+ L2ToL1MessageLimitReachedError,
36
+ NoteHashLimitReachedError,
37
+ NullifierCollisionError,
38
+ NullifierLimitReachedError,
39
+ } from '../side_effect_errors.js';
31
40
  import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
32
41
  import { PublicTxContext } from './public_tx_context.js';
42
+ import type { PublicTxSimulatorInterface } from './public_tx_simulator_interface.js';
33
43
 
34
44
  export type ProcessedPhase = {
35
45
  phase: TxExecutionPhase;
@@ -47,19 +57,69 @@ export type PublicTxResult = {
47
57
  /** Revert reason, if any */
48
58
  revertReason?: SimulationError;
49
59
  processedPhases: ProcessedPhase[];
60
+ logs: DebugLog[];
61
+ };
62
+
63
+ export type PublicTxSimulatorConfig = {
64
+ proverId: Fr;
65
+ doMerkleOperations: boolean;
66
+ skipFeeEnforcement: boolean;
67
+ clientInitiatedSimulation: boolean;
68
+ maxDebugLogMemoryReads: number;
50
69
  };
51
70
 
52
- export class PublicTxSimulator {
71
+ // The errors below are only thrown here in the public tx simulator,
72
+ // and only during revertible phases (revertible insertions, app logic and teardown).
73
+ // These are strictly "checked" errors (not exported and never propagated).
74
+ // They are used internally for control flow to trigger rollbacks to the post-setup state.
75
+
76
+ /**
77
+ * Error thrown when public tx simulation reverts in a known/checked way during revertible insertions.
78
+ */
79
+ class TxSimRevertibleInsertionsRevert extends Error {
80
+ constructor() {
81
+ super('Public Tx Simulation reverted during Revertible Insertions');
82
+ this.name = 'TxSimRevertibleInsertionsRevert';
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Error thrown when public tx simulation reverts during app logic.
88
+ */
89
+ class TxSimAppLogicRevert extends Error {
90
+ constructor() {
91
+ super('Public Tx Simulation reverted during App Logic');
92
+ this.name = 'TxSimAppLogicRevert';
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Error thrown when public tx simulation reverts during teardown.
98
+ */
99
+ class TxSimTeardownRevert extends Error {
100
+ constructor() {
101
+ super('Public Tx Simulation reverted during Teardown');
102
+ this.name = 'TxSimTeardownRevert';
103
+ }
104
+ }
105
+
106
+ export class PublicTxSimulator implements PublicTxSimulatorInterface {
53
107
  protected log: Logger;
108
+ private config: PublicTxSimulatorConfig;
54
109
 
55
110
  constructor(
56
- private merkleTree: MerkleTreeWriteOperations,
57
- private contractsDB: PublicContractsDB,
58
- private globalVariables: GlobalVariables,
59
- private doMerkleOperations: boolean = false,
60
- private skipFeeEnforcement: boolean = false,
61
- private clientInitiatedSimulation: boolean = false,
111
+ protected merkleTree: MerkleTreeWriteOperations,
112
+ protected contractsDB: PublicContractsDB,
113
+ protected globalVariables: GlobalVariables,
114
+ config?: Partial<PublicTxSimulatorConfig>,
62
115
  ) {
116
+ this.config = {
117
+ proverId: config?.proverId ?? Fr.ZERO,
118
+ doMerkleOperations: config?.doMerkleOperations ?? false,
119
+ skipFeeEnforcement: config?.skipFeeEnforcement ?? false,
120
+ clientInitiatedSimulation: config?.clientInitiatedSimulation ?? false,
121
+ maxDebugLogMemoryReads: config?.maxDebugLogMemoryReads ?? DEFAULT_MAX_DEBUG_LOG_MEMORY_READS,
122
+ };
63
123
  this.log = createLogger(`simulator:public_tx_simulator`);
64
124
  }
65
125
 
@@ -74,7 +134,11 @@ export class PublicTxSimulator {
74
134
  this.log.debug(`Simulating ${tx.publicFunctionCalldata.length} public calls for tx ${txHash}`, { txHash });
75
135
 
76
136
  // Create hinting DBs.
77
- const hints = new AvmExecutionHints(this.globalVariables, AvmTxHint.fromTx(tx, this.globalVariables.gasFees));
137
+ const hints = new AvmExecutionHints(
138
+ this.globalVariables,
139
+ AvmTxHint.fromTx(tx, this.globalVariables.gasFees),
140
+ ProtocolContractsList, // imported from file
141
+ );
78
142
  const hintingMerkleTree = await HintingMerkleWriteOperations.create(this.merkleTree, hints);
79
143
  const hintingTreesDB = new PublicTreesDB(hintingMerkleTree);
80
144
  const hintingContractsDB = new HintingPublicContractsDB(this.contractsDB, hints);
@@ -84,7 +148,9 @@ export class PublicTxSimulator {
84
148
  hintingContractsDB,
85
149
  tx,
86
150
  this.globalVariables,
87
- this.doMerkleOperations,
151
+ ProtocolContractsList, // imported from file
152
+ this.config.doMerkleOperations,
153
+ this.config.proverId,
88
154
  );
89
155
 
90
156
  // This will throw if there is a nullifier collision.
@@ -108,23 +174,28 @@ export class PublicTxSimulator {
108
174
  await context.state.fork();
109
175
 
110
176
  try {
111
- // This will throw if there is a nullifier collision.
177
+ // This will throw if there is a nullifier collision or other insertion error (limit reached).
112
178
  await this.insertRevertiblesFromPrivate(context, tx);
179
+
113
180
  // Only proceed with app logic if there was no revert during revertible insertion.
114
181
  if (context.hasPhase(TxExecutionPhase.APP_LOGIC)) {
115
182
  const appLogicResult = await this.simulatePhase(TxExecutionPhase.APP_LOGIC, context);
116
183
  processedPhases.push(appLogicResult);
117
184
  if (appLogicResult.reverted) {
118
- throw new Error(`App logic phase reverted! ${appLogicResult.revertReason?.message}`);
185
+ throw new TxSimAppLogicRevert();
119
186
  }
120
187
  }
121
- } catch (e) {
122
- this.log.debug(String(e));
123
- // We revert to the post-setup state.
124
- await context.state.discardForkedState();
125
- // But we also create a new fork so that the teardown phase can transparently
126
- // commit or rollback at the end of teardown.
127
- await context.state.fork();
188
+ } catch (e: any) {
189
+ if (e instanceof TxSimRevertibleInsertionsRevert || e instanceof TxSimAppLogicRevert) {
190
+ // We revert to the post-setup state.
191
+ await context.state.discardForkedState();
192
+ // But we also create a new fork so that the teardown phase can transparently
193
+ // commit or rollback at the end of teardown.
194
+ await context.state.fork();
195
+ } else {
196
+ // Unchecked/unknown error - re-throw as-is
197
+ throw e;
198
+ }
128
199
  }
129
200
 
130
201
  try {
@@ -132,25 +203,28 @@ export class PublicTxSimulator {
132
203
  const teardownResult = await this.simulatePhase(TxExecutionPhase.TEARDOWN, context);
133
204
  processedPhases.push(teardownResult);
134
205
  if (teardownResult.reverted) {
135
- throw new Error(`Teardown phase reverted! ${teardownResult.revertReason?.message}`);
206
+ throw new TxSimTeardownRevert();
136
207
  }
137
208
  }
138
-
139
209
  // We commit the forked state and we are done.
140
210
  await context.state.mergeForkedState();
141
- } catch (e) {
142
- this.log.debug(String(e));
143
- // We rollback to the post-setup state.
144
- await context.state.discardForkedState();
211
+ } catch (e: any) {
212
+ if (e instanceof TxSimTeardownRevert) {
213
+ // We revert to the post-setup state and we are done.
214
+ await context.state.discardForkedState();
215
+ } else {
216
+ // Unchecked/unknown error - re-throw as-is
217
+ throw e;
218
+ }
145
219
  }
146
220
 
147
221
  context.halt();
148
222
 
149
- if (context.getActualGasUsed().l2Gas > AVM_MAX_PROCESSABLE_L2_GAS) {
150
- throw new Error(
151
- `Transaction consumes ${context.getActualGasUsed().l2Gas} L2 gas, which exceeds the AVM maximum processable gas of ${AVM_MAX_PROCESSABLE_L2_GAS}`,
152
- );
153
- }
223
+ // Such transactions should be filtered by GasTxValidator.
224
+ assert(
225
+ context.getActualGasUsed().l2Gas <= AVM_MAX_PROCESSABLE_L2_GAS,
226
+ `Transaction consumes ${context.getActualGasUsed().l2Gas} L2 gas, which exceeds the AVM maximum processable gas of ${AVM_MAX_PROCESSABLE_L2_GAS}`,
227
+ );
154
228
  await this.payFee(context);
155
229
 
156
230
  const publicInputs = await context.generateAvmCircuitPublicInputs();
@@ -176,6 +250,7 @@ export class PublicTxSimulator {
176
250
  revertCode,
177
251
  revertReason: context.revertReason,
178
252
  processedPhases: processedPhases,
253
+ logs: context.state.getActiveStateManager().getLogs(),
179
254
  };
180
255
  } finally {
181
256
  // Make sure there are no new contracts in the tx-level cache.
@@ -308,7 +383,8 @@ export class PublicTxSimulator {
308
383
  request.isStaticCall,
309
384
  calldata,
310
385
  allocatedGas,
311
- this.clientInitiatedSimulation,
386
+ this.config.clientInitiatedSimulation,
387
+ this.config.maxDebugLogMemoryReads,
312
388
  );
313
389
  const avmCallResult = await simulator.execute();
314
390
  return avmCallResult.finalize();
@@ -345,42 +421,85 @@ export class PublicTxSimulator {
345
421
 
346
422
  /**
347
423
  * Insert the revertible accumulated data from private into the public state.
348
- * Start by forking state so we can rollback to the end of setup if app logic or teardown reverts.
424
+ * Throws TxSimRevertibleInsertionsRevert if there is some checked error during revertible insertions.
425
+ * This function checks for the following errors:
426
+ * - NullifierLimitReachedError
427
+ * - NullifierCollisionError
428
+ * - NoteHashLimitReachedError
429
+ * - L2ToL1MessageLimitReachedError
349
430
  */
350
- protected async insertRevertiblesFromPrivate(context: PublicTxContext, tx: Tx): /*success=*/ Promise<boolean> {
431
+ protected async insertRevertiblesFromPrivate(context: PublicTxContext, tx: Tx) {
351
432
  const stateManager = context.state.getActiveStateManager();
352
433
 
353
434
  try {
354
435
  for (const siloedNullifier of context.revertibleAccumulatedDataFromPrivate.nullifiers.filter(n => !n.isEmpty())) {
355
436
  await stateManager.writeSiloedNullifier(siloedNullifier);
356
437
  }
357
- } catch (e) {
358
- context.revert(
359
- TxExecutionPhase.APP_LOGIC,
360
- new SimulationError(
361
- `Nullifier collision encountered when inserting revertible nullifiers from private.\nDetails: ${String(e)}`,
362
- [],
363
- ),
364
- );
365
- throw e;
438
+ } catch (e: any) {
439
+ if (e instanceof NullifierLimitReachedError || e instanceof NullifierCollisionError) {
440
+ context.revert(
441
+ TxExecutionPhase.APP_LOGIC,
442
+ new SimulationError(
443
+ `Error encountered when inserting revertible nullifiers from private.\nDetails: ${e.message}`,
444
+ [],
445
+ ),
446
+ );
447
+ throw new TxSimRevertibleInsertionsRevert();
448
+ } else {
449
+ // Unchecked/unknown error - re-throw as-is
450
+ throw e;
451
+ }
366
452
  }
367
- for (const noteHash of context.revertibleAccumulatedDataFromPrivate.noteHashes) {
368
- if (!noteHash.isEmpty()) {
369
- // Revertible note hashes from private are not hashed with nonce, since private can't know their final position, only we can.
370
- await stateManager.writeSiloedNoteHash(noteHash);
453
+
454
+ try {
455
+ for (const noteHash of context.revertibleAccumulatedDataFromPrivate.noteHashes) {
456
+ if (!noteHash.isEmpty()) {
457
+ // Revertible note hashes from private are not hashed with nonce, since private can't know their final position, only we can.
458
+ await stateManager.writeSiloedNoteHash(noteHash);
459
+ }
460
+ }
461
+ } catch (e: any) {
462
+ if (e instanceof NoteHashLimitReachedError) {
463
+ context.revert(
464
+ TxExecutionPhase.APP_LOGIC,
465
+ new SimulationError(
466
+ `Error encountered when inserting revertible note hashes from private.\nDetails: ${e.message}`,
467
+ [],
468
+ ),
469
+ );
470
+ throw new TxSimRevertibleInsertionsRevert();
471
+ } else {
472
+ // Unchecked/unknown error - re-throw as-is
473
+ throw e;
371
474
  }
372
475
  }
373
- for (const l2ToL1Message of context.revertibleAccumulatedDataFromPrivate.l2ToL1Msgs) {
374
- if (!l2ToL1Message.isEmpty()) {
375
- stateManager.writeScopedL2ToL1Message(l2ToL1Message);
476
+
477
+ try {
478
+ for (const l2ToL1Message of context.revertibleAccumulatedDataFromPrivate.l2ToL1Msgs) {
479
+ if (!l2ToL1Message.isEmpty()) {
480
+ stateManager.writeScopedL2ToL1Message(l2ToL1Message);
481
+ }
482
+ }
483
+ } catch (e: any) {
484
+ if (e instanceof L2ToL1MessageLimitReachedError) {
485
+ context.revert(
486
+ TxExecutionPhase.APP_LOGIC,
487
+ new SimulationError(
488
+ `Error encountered when inserting revertible L2-to-L1 messages from private.\nDetails: ${e.message}`,
489
+ [],
490
+ ),
491
+ );
492
+ throw new TxSimRevertibleInsertionsRevert();
493
+ } else {
494
+ // Unchecked/unknown error - re-throw as-is
495
+ throw e;
376
496
  }
377
497
  }
498
+
378
499
  // add new contracts to the contracts db so that their functions may be found and called
379
500
  // FIXME(fcarreiro): this should conceptually use the hinted contracts db.
380
501
  // However things should work as they are now because the hinted db would still pick up the new contracts.
381
502
  await this.contractsDB.addNewRevertibleContracts(tx);
382
-
383
- return /*success=*/ true;
384
503
  }
385
504
 
386
505
  private async payFee(context: PublicTxContext) {
@@ -402,13 +521,12 @@ export class PublicTxSimulator {
402
521
  // When mocking the balance of the fee payer, the circuit should not be able to prove the simulation
403
522
 
404
523
  if (currentBalance.lt(txFee)) {
405
- if (!this.skipFeeEnforcement) {
406
- throw new Error(
407
- `Not enough balance for fee payer to pay for transaction (got ${currentBalance.toBigInt()} needs ${txFee.toBigInt()})`,
408
- );
409
- } else {
410
- currentBalance = txFee;
411
- }
524
+ // Without "skipFeeEnforcement", such transactions should be filtered by GasTxValidator.
525
+ assert(
526
+ this.config.skipFeeEnforcement,
527
+ `Not enough balance for fee payer to pay for transaction (got ${currentBalance.toBigInt()} needs ${txFee.toBigInt()})`,
528
+ );
529
+ currentBalance = txFee;
412
530
  }
413
531
 
414
532
  const updatedBalance = currentBalance.sub(txFee);
@@ -0,0 +1,11 @@
1
+ import type { Tx } from '@aztec/stdlib/tx';
2
+
3
+ import type { PublicTxResult } from './public_tx_simulator.js';
4
+
5
+ export interface PublicTxSimulatorInterface {
6
+ simulate(tx: Tx): Promise<PublicTxResult>;
7
+ }
8
+
9
+ export interface MeasuredPublicTxSimulatorInterface {
10
+ simulate(tx: Tx, txLabel: string): Promise<PublicTxResult>;
11
+ }
@@ -10,6 +10,7 @@ import type { PublicContractsDB } from '../public_db_sources.js';
10
10
  import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
11
11
  import { MeasuredPublicTxSimulator } from './measured_public_tx_simulator.js';
12
12
  import { PublicTxContext } from './public_tx_context.js';
13
+ import type { PublicTxSimulatorConfig } from './public_tx_simulator.js';
13
14
 
14
15
  /**
15
16
  * A public tx simulator that tracks runtime/production metrics with telemetry.
@@ -22,21 +23,11 @@ export class TelemetryPublicTxSimulator extends MeasuredPublicTxSimulator {
22
23
  merkleTree: MerkleTreeWriteOperations,
23
24
  contractsDB: PublicContractsDB,
24
25
  globalVariables: GlobalVariables,
25
- doMerkleOperations: boolean = false,
26
- skipFeeEnforcement: boolean = false,
27
- clientInitiatedSimulation: boolean = false,
28
26
  telemetryClient: TelemetryClient = getTelemetryClient(),
27
+ config?: Partial<PublicTxSimulatorConfig>,
29
28
  ) {
30
29
  const metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
31
- super(
32
- merkleTree,
33
- contractsDB,
34
- globalVariables,
35
- doMerkleOperations,
36
- skipFeeEnforcement,
37
- clientInitiatedSimulation,
38
- metrics,
39
- );
30
+ super(merkleTree, contractsDB, globalVariables, metrics, config);
40
31
  this.tracer = metrics.tracer;
41
32
  }
42
33
 
@@ -1,6 +1,96 @@
1
- export class SideEffectLimitReachedError extends Error {
1
+ import {
2
+ L1_TO_L2_MSG_TREE_LEAF_COUNT,
3
+ MAX_L2_TO_L1_MSGS_PER_TX,
4
+ MAX_NOTE_HASHES_PER_TX,
5
+ MAX_NULLIFIERS_PER_TX,
6
+ MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS,
7
+ NOTE_HASH_TREE_LEAF_COUNT,
8
+ } from '@aztec/constants';
9
+
10
+ import { CheckedPublicExecutionError } from './public_errors.js';
11
+
12
+ /**
13
+ * Any error that can be thrown during side effect insertion in public.
14
+ * Includes SideEffectLimitReachedError and NullifierCollisionError.
15
+ */
16
+ export abstract class SideEffectError extends CheckedPublicExecutionError {
17
+ constructor(message: string) {
18
+ super(message);
19
+ this.name = 'SideEffectInsertionError';
20
+ }
21
+ }
22
+
23
+ export class SideEffectLimitReachedError extends SideEffectError {
2
24
  constructor(sideEffectType: string, limit: number) {
3
25
  super(`Reached the limit (${limit}) on number of '${sideEffectType}' per tx`);
4
26
  this.name = 'SideEffectLimitReachedError';
5
27
  }
6
28
  }
29
+
30
+ export class MaxCallsToUniqueContractClassIdsError extends SideEffectLimitReachedError {
31
+ constructor() {
32
+ super('contract calls to unique class IDs', MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS);
33
+ this.name = 'MaxCallsToUniqueContractClassIdsError';
34
+ }
35
+ }
36
+
37
+ export class NullifierLimitReachedError extends SideEffectLimitReachedError {
38
+ constructor() {
39
+ super('nullifier', MAX_NULLIFIERS_PER_TX);
40
+ this.name = 'NullifierLimitReachedError';
41
+ }
42
+ }
43
+
44
+ export class NoteHashLimitReachedError extends SideEffectLimitReachedError {
45
+ constructor() {
46
+ super('note hash', MAX_NOTE_HASHES_PER_TX);
47
+ this.name = 'NoteHashLimitReachedError';
48
+ }
49
+ }
50
+
51
+ export class L2ToL1MessageLimitReachedError extends SideEffectLimitReachedError {
52
+ constructor() {
53
+ super('l2 to l1 message', MAX_L2_TO_L1_MSGS_PER_TX);
54
+ this.name = 'L2ToL1MessageLimitReachedError';
55
+ }
56
+ }
57
+
58
+ export class NullifierCollisionError extends SideEffectError {
59
+ constructor(message: string) {
60
+ super(`Nullifier collision: ${message}`);
61
+ this.name = 'NullifierCollisionError';
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Any error that can be thrown during side effect reads in public.
67
+ * Note: Thrown at state manager level and unknown by simulation, hence NOT considered
68
+ * CheckedPublicExecutionErrors. Currently only includes append-only tree reads.
69
+ */
70
+ export abstract class SideEffectReadError extends Error {
71
+ constructor(message: string) {
72
+ super(message);
73
+ this.name = 'SideEffectReadError';
74
+ }
75
+ }
76
+
77
+ export class IndexOutOfRangeError extends SideEffectReadError {
78
+ constructor(tree: string, index: number, limit: number) {
79
+ super(`Attempting to read index ${index} of ${tree} tree with maximum ${limit} leaves`);
80
+ this.name = 'IndexOutOfRangeError';
81
+ }
82
+ }
83
+
84
+ export class NoteHashIndexOutOfRangeError extends IndexOutOfRangeError {
85
+ constructor(index: number) {
86
+ super('note hash', index, NOTE_HASH_TREE_LEAF_COUNT);
87
+ this.name = 'NoteHashIndexOutOfRangeError';
88
+ }
89
+ }
90
+
91
+ export class L1ToL2MessageIndexOutOfRangeError extends IndexOutOfRangeError {
92
+ constructor(index: number) {
93
+ super('l1 to l2 message', index, L1_TO_L2_MSG_TREE_LEAF_COUNT);
94
+ this.name = 'L1ToL2MessageIndexOutOfRangeError';
95
+ }
96
+ }