@aztec/simulator 0.82.2 → 0.82.3-nightly.20250403

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 (155) hide show
  1. package/README.md +6 -0
  2. package/dest/private/acvm/oracle/oracle.d.ts +3 -2
  3. package/dest/private/acvm/oracle/oracle.d.ts.map +1 -1
  4. package/dest/private/acvm/oracle/oracle.js +9 -6
  5. package/dest/private/acvm/oracle/typed_oracle.d.ts +4 -3
  6. package/dest/private/acvm/oracle/typed_oracle.d.ts.map +1 -1
  7. package/dest/private/acvm/oracle/typed_oracle.js +4 -1
  8. package/dest/private/execution_data_provider.d.ts +20 -16
  9. package/dest/private/execution_data_provider.d.ts.map +1 -1
  10. package/dest/private/private_execution_oracle.d.ts +1 -1
  11. package/dest/private/private_execution_oracle.d.ts.map +1 -1
  12. package/dest/private/private_execution_oracle.js +2 -6
  13. package/dest/private/unconstrained_execution_oracle.d.ts +4 -2
  14. package/dest/private/unconstrained_execution_oracle.d.ts.map +1 -1
  15. package/dest/private/unconstrained_execution_oracle.js +5 -6
  16. package/dest/public/avm/avm_context.d.ts +3 -3
  17. package/dest/public/avm/avm_context.d.ts.map +1 -1
  18. package/dest/public/avm/avm_contract_call_result.d.ts +4 -2
  19. package/dest/public/avm/avm_contract_call_result.d.ts.map +1 -1
  20. package/dest/public/avm/avm_contract_call_result.js +9 -5
  21. package/dest/public/avm/avm_machine_state.d.ts +2 -0
  22. package/dest/public/avm/avm_machine_state.d.ts.map +1 -1
  23. package/dest/public/avm/avm_machine_state.js +2 -0
  24. package/dest/public/avm/avm_simulator.d.ts +2 -2
  25. package/dest/public/avm/avm_simulator.d.ts.map +1 -1
  26. package/dest/public/avm/avm_simulator.js +5 -6
  27. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts +2 -2
  28. package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
  29. package/dest/public/avm/fixtures/avm_simulation_tester.js +3 -4
  30. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +1 -2
  31. package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
  32. package/dest/public/avm/fixtures/base_avm_simulation_tester.js +0 -5
  33. package/dest/public/avm/fixtures/index.d.ts +6 -5
  34. package/dest/public/avm/fixtures/index.d.ts.map +1 -1
  35. package/dest/public/avm/fixtures/index.js +3 -3
  36. package/dest/public/avm/fixtures/simple_contract_data_source.d.ts +3 -2
  37. package/dest/public/avm/fixtures/simple_contract_data_source.d.ts.map +1 -1
  38. package/dest/public/avm/fixtures/simple_contract_data_source.js +30 -6
  39. package/dest/public/avm/index.d.ts +0 -1
  40. package/dest/public/avm/index.d.ts.map +1 -1
  41. package/dest/public/avm/index.js +0 -1
  42. package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
  43. package/dest/public/avm/opcodes/accrued_substate.js +1 -1
  44. package/dest/public/avm/opcodes/external_calls.d.ts.map +1 -1
  45. package/dest/public/avm/opcodes/external_calls.js +2 -0
  46. package/dest/public/avm/opcodes/memory.d.ts.map +1 -1
  47. package/dest/public/avm/opcodes/memory.js +8 -10
  48. package/dest/public/avm/serialization/instruction_serialization.d.ts +5 -2
  49. package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
  50. package/dest/public/avm/serialization/instruction_serialization.js +25 -7
  51. package/dest/public/avm/test_utils.d.ts +1 -1
  52. package/dest/public/avm/test_utils.d.ts.map +1 -1
  53. package/dest/public/executor_metrics.d.ts +11 -3
  54. package/dest/public/executor_metrics.d.ts.map +1 -1
  55. package/dest/public/executor_metrics.js +40 -6
  56. package/dest/public/executor_metrics_interface.d.ts +10 -0
  57. package/dest/public/executor_metrics_interface.d.ts.map +1 -0
  58. package/dest/public/executor_metrics_interface.js +1 -0
  59. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +12 -6
  60. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  61. package/dest/public/fixtures/public_tx_simulation_tester.js +39 -19
  62. package/dest/public/hinting_db_sources.d.ts +26 -3
  63. package/dest/public/hinting_db_sources.d.ts.map +1 -1
  64. package/dest/public/hinting_db_sources.js +134 -1
  65. package/dest/public/index.d.ts +1 -1
  66. package/dest/public/index.d.ts.map +1 -1
  67. package/dest/public/index.js +1 -1
  68. package/dest/public/public_db_sources.d.ts +2 -3
  69. package/dest/public/public_db_sources.d.ts.map +1 -1
  70. package/dest/public/public_db_sources.js +26 -16
  71. package/dest/public/public_processor/public_processor.d.ts +4 -4
  72. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  73. package/dest/public/public_processor/public_processor.js +7 -28
  74. package/dest/public/public_tx_simulator/apps_tests/amm_test.d.ts +9 -0
  75. package/dest/public/public_tx_simulator/apps_tests/amm_test.d.ts.map +1 -0
  76. package/dest/public/public_tx_simulator/apps_tests/amm_test.js +237 -0
  77. package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts +7 -0
  78. package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts.map +1 -0
  79. package/dest/public/public_tx_simulator/apps_tests/token_test.js +109 -0
  80. package/dest/public/public_tx_simulator/index.d.ts +3 -0
  81. package/dest/public/public_tx_simulator/index.d.ts.map +1 -0
  82. package/dest/public/public_tx_simulator/index.js +2 -0
  83. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +23 -0
  84. package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -0
  85. package/dest/public/public_tx_simulator/measured_public_tx_simulator.js +58 -0
  86. package/dest/public/public_tx_simulator/public_tx_context.d.ts +5 -5
  87. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  88. package/dest/public/public_tx_simulator/public_tx_context.js +10 -8
  89. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +16 -16
  90. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  91. package/dest/public/public_tx_simulator/public_tx_simulator.js +25 -65
  92. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts +19 -0
  93. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts.map +1 -0
  94. package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.js +39 -0
  95. package/dest/public/state_manager/index.d.ts +2 -0
  96. package/dest/public/state_manager/index.d.ts.map +1 -0
  97. package/dest/public/state_manager/index.js +1 -0
  98. package/dest/public/{avm/journal → state_manager}/nullifiers.d.ts +1 -1
  99. package/dest/public/state_manager/nullifiers.d.ts.map +1 -0
  100. package/dest/public/{avm/journal → state_manager}/public_storage.d.ts +1 -1
  101. package/dest/public/state_manager/public_storage.d.ts.map +1 -0
  102. package/dest/public/{avm/journal/journal.d.ts → state_manager/state_manager.d.ts} +10 -10
  103. package/dest/public/state_manager/state_manager.d.ts.map +1 -0
  104. package/dest/public/{avm/journal/journal.js → state_manager/state_manager.js} +5 -5
  105. package/dest/public/test_executor_metrics.d.ts +43 -0
  106. package/dest/public/test_executor_metrics.d.ts.map +1 -0
  107. package/dest/public/test_executor_metrics.js +158 -0
  108. package/package.json +14 -14
  109. package/src/private/acvm/oracle/oracle.ts +26 -5
  110. package/src/private/acvm/oracle/typed_oracle.ts +14 -3
  111. package/src/private/execution_data_provider.ts +34 -18
  112. package/src/private/private_execution_oracle.ts +2 -13
  113. package/src/private/unconstrained_execution_oracle.ts +22 -15
  114. package/src/public/avm/avm_context.ts +2 -2
  115. package/src/public/avm/avm_contract_call_result.ts +15 -3
  116. package/src/public/avm/avm_machine_state.ts +5 -0
  117. package/src/public/avm/avm_simulator.ts +20 -9
  118. package/src/public/avm/fixtures/avm_simulation_tester.ts +4 -4
  119. package/src/public/avm/fixtures/base_avm_simulation_tester.ts +1 -7
  120. package/src/public/avm/fixtures/index.ts +7 -7
  121. package/src/public/avm/fixtures/simple_contract_data_source.ts +33 -6
  122. package/src/public/avm/index.ts +0 -1
  123. package/src/public/avm/opcodes/accrued_substate.ts +1 -1
  124. package/src/public/avm/opcodes/external_calls.ts +3 -0
  125. package/src/public/avm/opcodes/memory.ts +8 -10
  126. package/src/public/avm/serialization/instruction_serialization.ts +24 -9
  127. package/src/public/avm/test_utils.ts +1 -1
  128. package/src/public/executor_metrics.ts +54 -6
  129. package/src/public/executor_metrics_interface.ts +15 -0
  130. package/src/public/fixtures/public_tx_simulation_tester.ts +74 -18
  131. package/src/public/hinting_db_sources.ts +228 -3
  132. package/src/public/index.ts +1 -1
  133. package/src/public/public_db_sources.ts +36 -23
  134. package/src/public/public_processor/public_processor.ts +8 -28
  135. package/src/public/public_tx_simulator/apps_tests/amm_test.ts +316 -0
  136. package/src/public/public_tx_simulator/apps_tests/token_test.ts +138 -0
  137. package/src/public/public_tx_simulator/index.ts +2 -0
  138. package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +111 -0
  139. package/src/public/public_tx_simulator/public_tx_context.ts +13 -17
  140. package/src/public/public_tx_simulator/public_tx_simulator.ts +35 -79
  141. package/src/public/public_tx_simulator/telemetry_public_tx_simulator.ts +62 -0
  142. package/src/public/state_manager/index.ts +1 -0
  143. package/src/public/{avm/journal → state_manager}/nullifiers.ts +1 -1
  144. package/src/public/{avm/journal → state_manager}/public_storage.ts +1 -1
  145. package/src/public/{avm/journal/journal.ts → state_manager/state_manager.ts} +20 -13
  146. package/src/public/test_executor_metrics.ts +222 -0
  147. package/dest/public/avm/journal/index.d.ts +0 -2
  148. package/dest/public/avm/journal/index.d.ts.map +0 -1
  149. package/dest/public/avm/journal/index.js +0 -1
  150. package/dest/public/avm/journal/journal.d.ts.map +0 -1
  151. package/dest/public/avm/journal/nullifiers.d.ts.map +0 -1
  152. package/dest/public/avm/journal/public_storage.d.ts.map +0 -1
  153. package/src/public/avm/journal/index.ts +0 -1
  154. /package/dest/public/{avm/journal → state_manager}/nullifiers.js +0 -0
  155. /package/dest/public/{avm/journal → state_manager}/public_storage.js +0 -0
@@ -1,6 +1,5 @@
1
1
  import type { Fr } from '@aztec/foundation/fields';
2
2
  import { type Logger, createLogger } from '@aztec/foundation/log';
3
- import { Timer } from '@aztec/foundation/timer';
4
3
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
5
4
  import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
6
5
  import {
@@ -14,7 +13,6 @@ import {
14
13
  import { SimulationError } from '@aztec/stdlib/errors';
15
14
  import type { Gas, GasUsed } from '@aztec/stdlib/gas';
16
15
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
17
- import type { AvmSimulationStats } from '@aztec/stdlib/stats';
18
16
  import {
19
17
  type GlobalVariables,
20
18
  NestedProcessReturnValues,
@@ -22,21 +20,20 @@ import {
22
20
  Tx,
23
21
  TxExecutionPhase,
24
22
  } from '@aztec/stdlib/tx';
25
- import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
26
23
 
27
24
  import { strict as assert } from 'assert';
28
25
 
29
26
  import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
30
27
  import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
31
- import { type AvmPersistableStateManager, AvmSimulator } from '../avm/index.js';
32
- import { NullifierCollisionError } from '../avm/journal/nullifiers.js';
33
- import { ExecutorMetrics } from '../executor_metrics.js';
28
+ import { AvmSimulator } from '../avm/index.js';
34
29
  import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
30
+ import { NullifierCollisionError } from '../state_manager/nullifiers.js';
31
+ import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
35
32
  import { PublicTxContext } from './public_tx_context.js';
36
33
 
37
34
  export type ProcessedPhase = {
38
35
  phase: TxExecutionPhase;
39
- durationMs: number;
36
+ durationMs?: number;
40
37
  returnValues: NestedProcessReturnValues[];
41
38
  reverted: boolean;
42
39
  revertReason?: SimulationError;
@@ -53,25 +50,18 @@ export type PublicTxResult = {
53
50
  };
54
51
 
55
52
  export class PublicTxSimulator {
56
- metrics: ExecutorMetrics;
57
-
58
- private log: Logger;
53
+ protected log: Logger;
59
54
 
60
55
  constructor(
61
56
  private treesDB: PublicTreesDB,
62
- private contractsDB: PublicContractsDB,
57
+ protected contractsDB: PublicContractsDB,
63
58
  private globalVariables: GlobalVariables,
64
59
  private doMerkleOperations: boolean = false,
65
60
  private skipFeeEnforcement: boolean = false,
66
- telemetryClient: TelemetryClient = getTelemetryClient(),
67
61
  ) {
68
62
  this.log = createLogger(`simulator:public_tx_simulator`);
69
- this.metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
70
63
  }
71
64
 
72
- get tracer(): Tracer {
73
- return this.metrics.tracer;
74
- }
75
65
  /**
76
66
  * Simulate a transaction's public portion including all of its phases.
77
67
  * @param tx - The transaction to simulate.
@@ -79,11 +69,9 @@ export class PublicTxSimulator {
79
69
  */
80
70
  public async simulate(tx: Tx): Promise<PublicTxResult> {
81
71
  try {
82
- const startTime = process.hrtime.bigint();
72
+ const txHash = await this.computeTxHash(tx);
83
73
 
84
- const txHash = await tx.getTxHash();
85
74
  this.log.debug(`Simulating ${tx.publicFunctionCalldata.length} public calls for tx ${txHash}`, { txHash });
86
-
87
75
  const context = await PublicTxContext.create(
88
76
  this.treesDB,
89
77
  this.contractsDB,
@@ -92,13 +80,7 @@ export class PublicTxSimulator {
92
80
  this.doMerkleOperations,
93
81
  );
94
82
 
95
- const nonRevertStart = process.hrtime.bigint();
96
- await this.insertNonRevertiblesFromPrivate(context);
97
- // add new contracts to the contracts db so that their functions may be found and called
98
- // TODO(#6464): Should we allow emitting contracts in the private setup phase?
99
- await this.contractsDB.addNewNonRevertibleContracts(tx);
100
- const nonRevertEnd = process.hrtime.bigint();
101
- this.metrics.recordPrivateEffectsInsertion(Number(nonRevertEnd - nonRevertStart) / 1_000, 'non-revertible');
83
+ await this.insertNonRevertiblesFromPrivate(context, tx);
102
84
 
103
85
  const processedPhases: ProcessedPhase[] = [];
104
86
  if (context.hasPhase(TxExecutionPhase.SETUP)) {
@@ -106,14 +88,8 @@ export class PublicTxSimulator {
106
88
  processedPhases.push(setupResult);
107
89
  }
108
90
 
109
- const revertStart = process.hrtime.bigint();
110
- const success = await this.insertRevertiblesFromPrivate(context);
91
+ const success = await this.insertRevertiblesFromPrivate(context, tx);
111
92
  if (success) {
112
- // add new contracts to the contracts db so that their functions may be found and called
113
- await this.contractsDB.addNewRevertibleContracts(tx);
114
- const revertEnd = process.hrtime.bigint();
115
- this.metrics.recordPrivateEffectsInsertion(Number(revertEnd - revertStart) / 1_000, 'revertible');
116
-
117
93
  // Only proceed with app logic if there was no revert during revertible insertion
118
94
  if (context.hasPhase(TxExecutionPhase.APP_LOGIC)) {
119
95
  const appLogicResult: ProcessedPhase = await this.simulateAppLogicPhase(context);
@@ -131,7 +107,7 @@ export class PublicTxSimulator {
131
107
  await context.halt();
132
108
  await this.payFee(context);
133
109
 
134
- const publicInputs = await context.generateAvmCircuitPublicInputs(await this.treesDB.getStateReference());
110
+ const publicInputs = await context.generateAvmCircuitPublicInputs();
135
111
  const avmProvingRequest = PublicTxSimulator.generateProvingRequest(publicInputs, context.hints);
136
112
 
137
113
  const revertCode = context.getFinalRevertCode();
@@ -142,11 +118,10 @@ export class PublicTxSimulator {
142
118
  // Commit contracts from this TX to the block-level cache and clear tx cache
143
119
  // If the tx reverted, only commit non-revertible contracts
144
120
  // NOTE: You can't create contracts in public, so this is only relevant for private-created contracts
121
+ // FIXME(fcarreiro): this should conceptually use the hinted contracts db.
122
+ // However things should work as they are now because the hinted db would still pick up the new contracts.
145
123
  this.contractsDB.commitContractsForTx(/*onlyNonRevertibles=*/ !revertCode.isOK());
146
124
 
147
- const endTime = process.hrtime.bigint();
148
- this.log.debug(`Public TX simulator took ${Number(endTime - startTime) / 1_000_000} ms\n`);
149
-
150
125
  return {
151
126
  avmProvingRequest,
152
127
  gasUsed: {
@@ -162,10 +137,16 @@ export class PublicTxSimulator {
162
137
  } finally {
163
138
  // Make sure there are no new contracts in the tx-level cache.
164
139
  // They should either be committed to block-level cache or cleared.
140
+ // FIXME(fcarreiro): this should conceptually use the hinted contracts db.
141
+ // However things should work as they are now because the hinted db would still pick up the new contracts.
165
142
  this.contractsDB.clearContractsForTx();
166
143
  }
167
144
  }
168
145
 
146
+ protected async computeTxHash(tx: Tx) {
147
+ return await tx.getTxHash();
148
+ }
149
+
169
150
  /**
170
151
  * Simulate the setup phase of a transaction's public execution.
171
152
  * @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
@@ -229,7 +210,7 @@ export class PublicTxSimulator {
229
210
  * @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
230
211
  * @returns The phase result.
231
212
  */
232
- private async simulatePhase(phase: TxExecutionPhase, context: PublicTxContext): Promise<ProcessedPhase> {
213
+ protected async simulatePhase(phase: TxExecutionPhase, context: PublicTxContext): Promise<ProcessedPhase> {
233
214
  const callRequests = context.getCallRequestsForPhase(phase);
234
215
 
235
216
  this.log.debug(`Processing phase ${TxExecutionPhase[phase]} for tx ${context.txHash}`, {
@@ -241,7 +222,6 @@ export class PublicTxSimulator {
241
222
  const returnValues: NestedProcessReturnValues[] = [];
242
223
  let reverted = false;
243
224
  let revertReason: SimulationError | undefined;
244
- const phaseTimer = new Timer();
245
225
  for (let i = callRequests.length - 1; i >= 0; i--) {
246
226
  if (reverted) {
247
227
  break;
@@ -261,7 +241,6 @@ export class PublicTxSimulator {
261
241
 
262
242
  return {
263
243
  phase,
264
- durationMs: phaseTimer.ms(),
265
244
  returnValues,
266
245
  reverted,
267
246
  revertReason,
@@ -275,13 +254,7 @@ export class PublicTxSimulator {
275
254
  * @param callRequest - The public function call request, including the calldata.
276
255
  * @returns The result of execution.
277
256
  */
278
- @trackSpan('PublicTxSimulator.simulateEnqueuedCall', (phase, context, callRequest) => ({
279
- [Attributes.TX_HASH]: context.txHash.toString(),
280
- [Attributes.TARGET_ADDRESS]: callRequest.request.contractAddress.toString(),
281
- [Attributes.SENDER_ADDRESS]: callRequest.request.msgSender.toString(),
282
- [Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
283
- }))
284
- private async simulateEnqueuedCall(
257
+ protected async simulateEnqueuedCall(
285
258
  phase: TxExecutionPhase,
286
259
  context: PublicTxContext,
287
260
  callRequest: PublicCallRequestWithCalldata,
@@ -335,20 +308,13 @@ export class PublicTxSimulator {
335
308
  * while still simulating phases and generating a proving request.
336
309
  *
337
310
  * @param stateManager - The state manager for AvmSimulation
338
- * @param context - The context of the currently executing public transaction portion
339
311
  * @param callRequest - The public function call request, including the calldata.
340
312
  * @param allocatedGas - The gas allocated to the enqueued call
341
313
  * @param fnName - The name of the function
342
314
  * @returns The result of execution.
343
315
  */
344
- @trackSpan(
345
- 'PublicTxSimulator.simulateEnqueuedCallInternal',
346
- (_stateManager, _callRequest, _allocatedGas, _transactionFee, fnName) => ({
347
- [Attributes.APP_CIRCUIT_NAME]: fnName,
348
- }),
349
- )
350
- private async simulateEnqueuedCallInternal(
351
- stateManager: AvmPersistableStateManager,
316
+ protected async simulateEnqueuedCallInternal(
317
+ stateManager: PublicPersistableStateManager,
352
318
  { request, calldata }: PublicCallRequestWithCalldata,
353
319
  allocatedGas: Gas,
354
320
  transactionFee: Fr,
@@ -360,7 +326,6 @@ export class PublicTxSimulator {
360
326
  this.log.debug(
361
327
  `Executing enqueued public call to external function ${fnName}@${address} with ${allocatedGas.l2Gas} allocated L2 gas.`,
362
328
  );
363
- const timer = new Timer();
364
329
 
365
330
  const simulator = await AvmSimulator.create(
366
331
  stateManager,
@@ -373,32 +338,13 @@ export class PublicTxSimulator {
373
338
  allocatedGas,
374
339
  );
375
340
  const avmCallResult = await simulator.execute();
376
- const result = avmCallResult.finalize();
377
-
378
- this.log.verbose(
379
- result.reverted
380
- ? `Simulation of enqueued public call ${fnName} reverted with reason ${result.revertReason}.`
381
- : `Simulation of enqueued public call ${fnName} completed successfully.`,
382
- {
383
- eventName: 'avm-simulation',
384
- appCircuitName: fnName,
385
- duration: timer.ms(),
386
- } satisfies AvmSimulationStats,
387
- );
388
-
389
- if (result.reverted) {
390
- this.metrics.recordFunctionSimulationFailure();
391
- } else {
392
- this.metrics.recordFunctionSimulation(timer.ms(), allocatedGas.sub(result.gasLeft).l2Gas, fnName);
393
- }
394
-
395
- return result;
341
+ return avmCallResult.finalize();
396
342
  }
397
343
 
398
344
  /**
399
345
  * Insert the non-revertible accumulated data from private into the public state.
400
346
  */
401
- public async insertNonRevertiblesFromPrivate(context: PublicTxContext) {
347
+ protected async insertNonRevertiblesFromPrivate(context: PublicTxContext, tx: Tx) {
402
348
  const stateManager = context.state.getActiveStateManager();
403
349
  try {
404
350
  await stateManager.writeSiloedNullifiersFromPrivate(context.nonRevertibleAccumulatedDataFromPrivate.nullifiers);
@@ -414,13 +360,18 @@ export class PublicTxSimulator {
414
360
  await stateManager.writeUniqueNoteHash(noteHash);
415
361
  }
416
362
  }
363
+ // add new contracts to the contracts db so that their functions may be found and called
364
+ // TODO(#6464): Should we allow emitting contracts in the private setup phase?
365
+ // FIXME(fcarreiro): this should conceptually use the hinted contracts db.
366
+ // However things should work as they are now because the hinted db would still pick up the new contracts.
367
+ await this.contractsDB.addNewNonRevertibleContracts(tx);
417
368
  }
418
369
 
419
370
  /**
420
371
  * Insert the revertible accumulated data from private into the public state.
421
372
  * Start by forking state so we can rollback to the end of setup if app logic or teardown reverts.
422
373
  */
423
- public async insertRevertiblesFromPrivate(context: PublicTxContext): /*success=*/ Promise<boolean> {
374
+ protected async insertRevertiblesFromPrivate(context: PublicTxContext, tx: Tx): /*success=*/ Promise<boolean> {
424
375
  // Fork the state manager so we can rollback to end of setup if app logic reverts.
425
376
  await context.state.fork();
426
377
  const stateManager = context.state.getActiveStateManager();
@@ -448,6 +399,11 @@ export class PublicTxSimulator {
448
399
  await stateManager.writeSiloedNoteHash(noteHash);
449
400
  }
450
401
  }
402
+ // add new contracts to the contracts db so that their functions may be found and called
403
+ // FIXME(fcarreiro): this should conceptually use the hinted contracts db.
404
+ // However things should work as they are now because the hinted db would still pick up the new contracts.
405
+ await this.contractsDB.addNewRevertibleContracts(tx);
406
+
451
407
  return /*success=*/ true;
452
408
  }
453
409
 
@@ -0,0 +1,62 @@
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { Gas } from '@aztec/stdlib/gas';
3
+ import { type GlobalVariables, PublicCallRequestWithCalldata, TxExecutionPhase } from '@aztec/stdlib/tx';
4
+ import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
5
+
6
+ import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
7
+ import { ExecutorMetrics } from '../executor_metrics.js';
8
+ import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
9
+ import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
10
+ import { MeasuredPublicTxSimulator } from './measured_public_tx_simulator.js';
11
+ import { PublicTxContext } from './public_tx_context.js';
12
+
13
+ /**
14
+ * A public tx simulator that tracks runtime/production metrics with telemetry.
15
+ */
16
+ export class TelemetryPublicTxSimulator extends MeasuredPublicTxSimulator {
17
+ /* tracer needed by trackSpans */
18
+ public readonly tracer: Tracer;
19
+
20
+ constructor(
21
+ treesDB: PublicTreesDB,
22
+ contractsDB: PublicContractsDB,
23
+ globalVariables: GlobalVariables,
24
+ doMerkleOperations: boolean = false,
25
+ skipFeeEnforcement: boolean = false,
26
+ telemetryClient: TelemetryClient = getTelemetryClient(),
27
+ ) {
28
+ const metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
29
+ super(treesDB, contractsDB, globalVariables, doMerkleOperations, skipFeeEnforcement, metrics);
30
+ this.tracer = metrics.tracer;
31
+ }
32
+
33
+ @trackSpan('PublicTxSimulator.simulateEnqueuedCall', (phase, context, callRequest) => ({
34
+ [Attributes.TX_HASH]: context.txHash.toString(),
35
+ [Attributes.TARGET_ADDRESS]: callRequest.request.contractAddress.toString(),
36
+ [Attributes.SENDER_ADDRESS]: callRequest.request.msgSender.toString(),
37
+ [Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
38
+ }))
39
+ protected override async simulateEnqueuedCall(
40
+ phase: TxExecutionPhase,
41
+ context: PublicTxContext,
42
+ callRequest: PublicCallRequestWithCalldata,
43
+ ): Promise<AvmFinalizedCallResult> {
44
+ return await super.simulateEnqueuedCall(phase, context, callRequest);
45
+ }
46
+
47
+ @trackSpan(
48
+ 'PublicTxSimulator.simulateEnqueuedCallInternal',
49
+ (_stateManager, _callRequest, _allocatedGas, _transactionFee, fnName) => ({
50
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
51
+ }),
52
+ )
53
+ protected override async simulateEnqueuedCallInternal(
54
+ stateManager: PublicPersistableStateManager,
55
+ callRequest: PublicCallRequestWithCalldata,
56
+ allocatedGas: Gas,
57
+ transactionFee: Fr,
58
+ fnName: string,
59
+ ): Promise<AvmFinalizedCallResult> {
60
+ return await super.simulateEnqueuedCallInternal(stateManager, callRequest, allocatedGas, transactionFee, fnName);
61
+ }
62
+ }
@@ -0,0 +1 @@
1
+ export * from './state_manager.js';
@@ -1,6 +1,6 @@
1
1
  import type { Fr } from '@aztec/foundation/fields';
2
2
 
3
- import type { PublicTreesDB } from '../../public_db_sources.js';
3
+ import type { PublicTreesDB } from '../public_db_sources.js';
4
4
 
5
5
  /**
6
6
  * A class to manage new nullifier staging and existence checks during a contract call's AVM simulation.
@@ -1,7 +1,7 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
2
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
3
 
4
- import type { PublicStateDBInterface } from '../../../common/db_interfaces.js';
4
+ import type { PublicStateDBInterface } from '../../common/db_interfaces.js';
5
5
 
6
6
  type PublicStorageReadResult = {
7
7
  value: Fr;
@@ -28,11 +28,11 @@ import { MerkleTreeId } from '@aztec/stdlib/trees';
28
28
 
29
29
  import { strict as assert } from 'assert';
30
30
 
31
- import { getPublicFunctionDebugName } from '../../../common/debug_fn_name.js';
32
- import type { PublicTreesDB } from '../../../public/public_db_sources.js';
33
- import type { PublicContractsDBInterface } from '../../../server.js';
34
- import type { PublicSideEffectTraceInterface } from '../../side_effect_trace_interface.js';
35
- import type { AvmExecutionEnvironment } from '../avm_execution_environment.js';
31
+ import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
32
+ import type { PublicContractsDBInterface } from '../../server.js';
33
+ import type { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js';
34
+ import type { PublicTreesDB } from '../public_db_sources.js';
35
+ import type { PublicSideEffectTraceInterface } from '../side_effect_trace_interface.js';
36
36
  import { NullifierCollisionError, NullifierManager } from './nullifiers.js';
37
37
  import { PublicStorage } from './public_storage.js';
38
38
 
@@ -45,8 +45,8 @@ import { PublicStorage } from './public_storage.js';
45
45
  *
46
46
  * Manages merging of successful/reverted child state into current state.
47
47
  */
48
- export class AvmPersistableStateManager {
49
- private readonly log = createLogger('simulator:avm:state_manager');
48
+ export class PublicPersistableStateManager {
49
+ private readonly log = createLogger('simulator:state_manager');
50
50
 
51
51
  /** Make sure a forked state is never merged twice. */
52
52
  private alreadyMergedIntoParent = false;
@@ -72,8 +72,15 @@ export class AvmPersistableStateManager {
72
72
  doMerkleOperations: boolean = false,
73
73
  firstNullifier: Fr,
74
74
  blockNumber: number,
75
- ): AvmPersistableStateManager {
76
- return new AvmPersistableStateManager(treesDB, contractsDB, trace, firstNullifier, blockNumber, doMerkleOperations);
75
+ ): PublicPersistableStateManager {
76
+ return new PublicPersistableStateManager(
77
+ treesDB,
78
+ contractsDB,
79
+ trace,
80
+ firstNullifier,
81
+ blockNumber,
82
+ doMerkleOperations,
83
+ );
77
84
  }
78
85
 
79
86
  // DO NOT USE!
@@ -87,7 +94,7 @@ export class AvmPersistableStateManager {
87
94
  */
88
95
  public async fork() {
89
96
  await this.treesDB.createCheckpoint();
90
- return new AvmPersistableStateManager(
97
+ return new PublicPersistableStateManager(
91
98
  this.treesDB,
92
99
  this.contractsDB,
93
100
  this.trace.fork(),
@@ -102,18 +109,18 @@ export class AvmPersistableStateManager {
102
109
  /**
103
110
  * Accept forked world state modifications & traced side effects / hints
104
111
  */
105
- public async merge(forkedState: AvmPersistableStateManager) {
112
+ public async merge(forkedState: PublicPersistableStateManager) {
106
113
  await this._merge(forkedState, /*reverted=*/ false);
107
114
  }
108
115
 
109
116
  /**
110
117
  * Reject forked world state modifications & traced side effects, keep traced hints
111
118
  */
112
- public async reject(forkedState: AvmPersistableStateManager) {
119
+ public async reject(forkedState: PublicPersistableStateManager) {
113
120
  await this._merge(forkedState, /*reverted=*/ true);
114
121
  }
115
122
 
116
- private async _merge(forkedState: AvmPersistableStateManager, reverted: boolean) {
123
+ private async _merge(forkedState: PublicPersistableStateManager, reverted: boolean) {
117
124
  // sanity check to avoid merging the same forked trace twice
118
125
  assert(
119
126
  !forkedState.alreadyMergedIntoParent,
@@ -0,0 +1,222 @@
1
+ import { sum } from '@aztec/foundation/collection';
2
+ import { type Logger, createLogger } from '@aztec/foundation/log';
3
+ import { Timer } from '@aztec/foundation/timer';
4
+ import type { RevertCode } from '@aztec/stdlib/avm';
5
+
6
+ import { strict as assert } from 'assert';
7
+
8
+ import type { ExecutorMetricsInterface } from './executor_metrics_interface.js';
9
+
10
+ export interface PublicEnqueuedCallMetrics {
11
+ fnName: string;
12
+ durationMs: number;
13
+ manaUsed: number;
14
+ totalInstructions: number;
15
+ reverted: boolean;
16
+ }
17
+
18
+ export interface PublicTxMetrics {
19
+ totalDurationMs: number;
20
+ manaUsed: number;
21
+ totalInstructions: number;
22
+ txHashMs: number | undefined;
23
+ nonRevertiblePrivateInsertionsUs: number | undefined;
24
+ revertiblePrivateInsertionsUs: number | undefined;
25
+ enqueuedCalls: PublicEnqueuedCallMetrics[];
26
+ revertedCode: RevertCode | undefined;
27
+ }
28
+
29
+ const NUM_SPACES = 4;
30
+ const H1 = '# ';
31
+ const H2 = '\n## ';
32
+ const INDENT = ' '.repeat(NUM_SPACES);
33
+ const INDENT0 = '- ';
34
+ const INDENT1 = INDENT + '- ';
35
+ const INDENT2 = INDENT + INDENT + '- ';
36
+ const H_LINE = '\n---------------------------------------------------------------------';
37
+
38
+ export enum PublicTxMetricsFilter {
39
+ ALL,
40
+ TOTALS,
41
+ DURATIONS,
42
+ INSTRUCTIONS,
43
+ }
44
+
45
+ export class TestExecutorMetrics implements ExecutorMetricsInterface {
46
+ private logger: Logger;
47
+ // tx label -> tx metrics
48
+ private txMetrics: Map<string, PublicTxMetrics> = new Map();
49
+ private currentTxLabel: string | undefined;
50
+ private txTimer: Timer | undefined;
51
+
52
+ constructor() {
53
+ this.logger = createLogger(`simulator:test_executor_metrics`);
54
+ }
55
+
56
+ startRecordingTxSimulation(txLabel: string) {
57
+ assert(!this.currentTxLabel, 'Cannot start recording tx simulation when another is live');
58
+ assert(!this.txMetrics.has(txLabel), 'Cannot start recording metrics for tx with duplicate label');
59
+ this.txMetrics.set(txLabel, {
60
+ totalDurationMs: 0,
61
+ manaUsed: 0,
62
+ totalInstructions: 0,
63
+ txHashMs: undefined,
64
+ nonRevertiblePrivateInsertionsUs: undefined,
65
+ revertiblePrivateInsertionsUs: undefined,
66
+ enqueuedCalls: [],
67
+ revertedCode: undefined,
68
+ });
69
+ this.currentTxLabel = txLabel;
70
+ this.txTimer = new Timer();
71
+ }
72
+
73
+ stopRecordingTxSimulation(txLabel: string, revertedCode?: RevertCode) {
74
+ assert(this.currentTxLabel === txLabel, 'Cannot stop recording metrics for tx when another is live');
75
+
76
+ const txMetrics = this.txMetrics.get(txLabel)!;
77
+
78
+ // total duration of tx
79
+ txMetrics.totalDurationMs = this.txTimer!.ms();
80
+ this.logger.debug(`Public TX simulation of ${txLabel} took ${txMetrics.totalDurationMs}ms`);
81
+
82
+ // add manaUsed across all enqueued calls
83
+ txMetrics.manaUsed = sum(txMetrics.enqueuedCalls.map(call => call.manaUsed));
84
+ // add totalInstructions across all enqueued calls
85
+ txMetrics.totalInstructions = sum(txMetrics.enqueuedCalls.map(call => call.totalInstructions));
86
+ txMetrics.revertedCode = revertedCode;
87
+
88
+ this.currentTxLabel = undefined;
89
+ }
90
+
91
+ recordEnqueuedCallSimulation(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number) {
92
+ this.#recordEnqueuedCallSimulation(fnName, durationMs, manaUsed, totalInstructions, false);
93
+ }
94
+
95
+ recordEnqueuedCallSimulationFailure(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number) {
96
+ this.#recordEnqueuedCallSimulation(fnName, durationMs, manaUsed, totalInstructions, true);
97
+ }
98
+
99
+ #recordEnqueuedCallSimulation(
100
+ fnName: string,
101
+ durationMs: number,
102
+ manaUsed: number,
103
+ totalInstructions: number,
104
+ reverted: boolean,
105
+ ) {
106
+ assert(this.currentTxLabel, 'Cannot record enqueued call simulation when no tx is live');
107
+ const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
108
+ txMetrics.enqueuedCalls.push({
109
+ fnName,
110
+ durationMs,
111
+ manaUsed,
112
+ totalInstructions,
113
+ reverted,
114
+ });
115
+ }
116
+
117
+ recordTxHashComputation(durationMs: number) {
118
+ assert(this.currentTxLabel, 'Cannot record tx hash computation time when no tx is live');
119
+ const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
120
+ assert(txMetrics.txHashMs === undefined, 'Cannot RE-record tx hash computation time');
121
+ txMetrics.txHashMs = durationMs;
122
+ }
123
+
124
+ recordPrivateEffectsInsertion(durationUs: number, type: 'revertible' | 'non-revertible') {
125
+ assert(this.currentTxLabel, 'Cannot record private effects insertion when no tx is live');
126
+ const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
127
+ if (type === 'revertible') {
128
+ assert(
129
+ txMetrics.revertiblePrivateInsertionsUs === undefined,
130
+ 'Cannot RE-record revertible insertions of private effects',
131
+ );
132
+ txMetrics.revertiblePrivateInsertionsUs = durationUs;
133
+ } else {
134
+ assert(
135
+ txMetrics.nonRevertiblePrivateInsertionsUs === undefined,
136
+ 'Cannot RE-record non-revertible insertions of private effects',
137
+ );
138
+ txMetrics.nonRevertiblePrivateInsertionsUs = durationUs;
139
+ }
140
+ }
141
+
142
+ prettyPrint(filter: PublicTxMetricsFilter = PublicTxMetricsFilter.ALL) {
143
+ this.logger.info(this.toPrettyString(filter));
144
+ }
145
+
146
+ toPrettyString(filter: PublicTxMetricsFilter = PublicTxMetricsFilter.ALL) {
147
+ let pretty = '';
148
+ //pretty += H_LINE + '\n';
149
+ pretty += `${H1}Public TX Simulation Metrics (${PublicTxMetricsFilter[filter]})\n`;
150
+ for (const [txLabel, txMetrics] of this.txMetrics.entries()) {
151
+ //pretty += H_LINE + '\n';
152
+ pretty += `${H2}TX Label: ${txLabel}\n`;
153
+ if (
154
+ filter == PublicTxMetricsFilter.DURATIONS ||
155
+ filter === PublicTxMetricsFilter.TOTALS ||
156
+ filter === PublicTxMetricsFilter.ALL
157
+ ) {
158
+ pretty += `${INDENT0}Total duration: ${fmtNum(txMetrics.totalDurationMs, 'ms')}\n`;
159
+ }
160
+ if (filter === PublicTxMetricsFilter.TOTALS || filter === PublicTxMetricsFilter.ALL) {
161
+ pretty += `${INDENT0}Total mana used: ${fmtNum(txMetrics.manaUsed)}\n`;
162
+ const manaPerSecond = Math.round((txMetrics.manaUsed * 1000) / txMetrics.totalDurationMs);
163
+ pretty += `${INDENT0}Mana per second: ${fmtNum(manaPerSecond)}\n`;
164
+ }
165
+
166
+ if (
167
+ filter === PublicTxMetricsFilter.INSTRUCTIONS ||
168
+ filter === PublicTxMetricsFilter.TOTALS ||
169
+ filter === PublicTxMetricsFilter.ALL
170
+ ) {
171
+ pretty += `${INDENT0}Total instructions executed: ${fmtNum(txMetrics.totalInstructions)}\n`;
172
+ }
173
+ if (filter === PublicTxMetricsFilter.DURATIONS || filter === PublicTxMetricsFilter.ALL) {
174
+ pretty += `${INDENT0}Tx hash computation: ${fmtNum(txMetrics.txHashMs!, 'ms')}\n`;
175
+ pretty += `${INDENT0}Private insertions:\n`;
176
+ pretty += `${INDENT1}Non-revertible: ${fmtNum(txMetrics.nonRevertiblePrivateInsertionsUs! / 1_000, 'ms')}\n`;
177
+ pretty += `${INDENT1}Revertible: ${fmtNum(txMetrics.revertiblePrivateInsertionsUs! / 1_000, 'ms')}\n`;
178
+ }
179
+ if (filter !== PublicTxMetricsFilter.TOTALS) {
180
+ // totals exclude enqueued calls
181
+ pretty += this.#enqueuedCallsToPrettyString(txMetrics, filter);
182
+ }
183
+ if (txMetrics.revertedCode !== undefined && !txMetrics.revertedCode.isOK()) {
184
+ pretty += `${INDENT0}Reverted code: ${txMetrics.revertedCode?.getDescription()}\n`;
185
+ }
186
+ pretty += H_LINE + '\n';
187
+ }
188
+ return pretty;
189
+ }
190
+
191
+ #enqueuedCallsToPrettyString(txMetrics: PublicTxMetrics, filter: PublicTxMetricsFilter) {
192
+ let pretty = '';
193
+ pretty += `${INDENT0}Enqueued public calls:\n`;
194
+ for (const enqueuedCall of txMetrics.enqueuedCalls) {
195
+ pretty += `${INDENT1}**Fn: ${enqueuedCall.fnName}**\n`;
196
+ if (filter === PublicTxMetricsFilter.DURATIONS || filter === PublicTxMetricsFilter.ALL) {
197
+ pretty += `${INDENT2}Duration: ${fmtNum(enqueuedCall.durationMs, 'ms')}\n`;
198
+ }
199
+ if (filter === PublicTxMetricsFilter.ALL) {
200
+ pretty += `${INDENT2}Mana used: ${fmtNum(enqueuedCall.manaUsed)}\n`;
201
+ const manaPerSecond = Math.round((enqueuedCall.manaUsed * 1000) / enqueuedCall.durationMs);
202
+ pretty += `${INDENT2}Mana per second: ${fmtNum(manaPerSecond)}\n`;
203
+ }
204
+
205
+ if (filter === PublicTxMetricsFilter.INSTRUCTIONS || filter === PublicTxMetricsFilter.ALL) {
206
+ pretty += `${INDENT2}Instructions executed: ${fmtNum(enqueuedCall.totalInstructions)}\n`;
207
+ }
208
+ if (enqueuedCall.reverted) {
209
+ pretty += `${INDENT2}Reverted!\n`;
210
+ }
211
+ }
212
+ return pretty;
213
+ }
214
+
215
+ toJSON(indent = 2) {
216
+ return JSON.stringify(Object.fromEntries(this.txMetrics.entries()), null, indent);
217
+ }
218
+ }
219
+
220
+ function fmtNum(num: number, unit?: string) {
221
+ return `\`${num.toLocaleString()}${unit ? ` ${unit}` : ''}\``;
222
+ }
@@ -1,2 +0,0 @@
1
- export * from './journal.js';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/public/avm/journal/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
@@ -1 +0,0 @@
1
- export * from './journal.js';