@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
@@ -9,15 +9,15 @@ import { NativeWorldStateService } from '@aztec/world-state';
9
9
  import { SideEffectTrace } from '../../../public/side_effect_trace.js';
10
10
  import type { AvmContractCallResult } from '../../avm/avm_contract_call_result.js';
11
11
  import {
12
+ DEFAULT_BLOCK_NUMBER,
12
13
  getContractFunctionAbi,
13
14
  getFunctionSelector,
14
15
  initContext,
15
16
  initExecutionEnvironment,
16
17
  resolveContractAssertionMessage,
17
18
  } from '../../avm/fixtures/index.js';
18
- import { AvmPersistableStateManager } from '../../avm/journal/journal.js';
19
- import { DEFAULT_BLOCK_NUMBER } from '../../fixtures/public_tx_simulation_tester.js';
20
19
  import { PublicContractsDB, PublicTreesDB } from '../../public_db_sources.js';
20
+ import { PublicPersistableStateManager } from '../../state_manager/state_manager.js';
21
21
  import { AvmSimulator } from '../avm_simulator.js';
22
22
  import { BaseAvmSimulationTester } from './base_avm_simulation_tester.js';
23
23
  import { SimpleContractDataSource } from './simple_contract_data_source.js';
@@ -34,7 +34,7 @@ export class AvmSimulationTester extends BaseAvmSimulationTester {
34
34
  constructor(
35
35
  contractDataSource: SimpleContractDataSource,
36
36
  merkleTrees: MerkleTreeWriteOperations,
37
- private stateManager: AvmPersistableStateManager,
37
+ private stateManager: PublicPersistableStateManager,
38
38
  ) {
39
39
  super(contractDataSource, merkleTrees);
40
40
  }
@@ -47,7 +47,7 @@ export class AvmSimulationTester extends BaseAvmSimulationTester {
47
47
  const trace = new SideEffectTrace();
48
48
  const firstNullifier = new Fr(420000);
49
49
 
50
- const stateManager = AvmPersistableStateManager.create(
50
+ const stateManager = PublicPersistableStateManager.create(
51
51
  treesDB,
52
52
  contractsDB,
53
53
  trace,
@@ -6,7 +6,7 @@ import { computeFeePayerBalanceStorageSlot, getCanonicalFeeJuice } from '@aztec/
6
6
  import type { ContractArtifact } from '@aztec/stdlib/abi';
7
7
  import { PublicDataWrite } from '@aztec/stdlib/avm';
8
8
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
9
- import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
9
+ import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
10
10
  import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/stdlib/hash';
11
11
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
12
12
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -86,12 +86,6 @@ export abstract class BaseAvmSimulationTester {
86
86
  return feeJuice.instance;
87
87
  }
88
88
 
89
- addContractClass(contractClass: ContractClassPublic, contractArtifact: ContractArtifact): Promise<void> {
90
- this.logger.debug(`Adding contract class with Id ${contractClass.id}`);
91
- this.contractDataSource.addContractArtifact(contractClass.id, contractArtifact);
92
- return this.contractDataSource.addContractClass(contractClass);
93
- }
94
-
95
89
  async addContractInstance(contractInstance: ContractInstanceWithAddress, skipNullifierInsertion = false) {
96
90
  if (!skipNullifierInsertion) {
97
91
  await this.insertContractAddressNullifier(contractInstance.address);
@@ -28,26 +28,26 @@ import { mock } from 'jest-mock-extended';
28
28
  import merge from 'lodash.merge';
29
29
 
30
30
  import { resolveAssertionMessageFromRevertData, traverseCauseChain } from '../../../common/index.js';
31
- import { DEFAULT_BLOCK_NUMBER } from '../../fixtures/public_tx_simulation_tester.js';
32
31
  import type { PublicContractsDB, PublicTreesDB } from '../../public_db_sources.js';
33
32
  import type { PublicSideEffectTraceInterface } from '../../side_effect_trace_interface.js';
33
+ import { NullifierManager } from '../../state_manager/nullifiers.js';
34
+ import { PublicStorage } from '../../state_manager/public_storage.js';
35
+ import { PublicPersistableStateManager } from '../../state_manager/state_manager.js';
34
36
  import { AvmContext } from '../avm_context.js';
35
37
  import { AvmExecutionEnvironment } from '../avm_execution_environment.js';
36
38
  import { AvmMachineState } from '../avm_machine_state.js';
37
39
  import { Field, Uint8, Uint32, Uint64 } from '../avm_memory_types.js';
38
40
  import { AvmSimulator } from '../avm_simulator.js';
39
41
  import type { AvmRevertReason } from '../errors.js';
40
- import { AvmPersistableStateManager } from '../journal/journal.js';
41
- import { NullifierManager } from '../journal/nullifiers.js';
42
- import { PublicStorage } from '../journal/public_storage.js';
43
42
 
44
43
  export const PUBLIC_DISPATCH_FN_NAME = 'public_dispatch';
44
+ export const DEFAULT_BLOCK_NUMBER = 42;
45
45
 
46
46
  /**
47
47
  * Create a new AVM context with default values.
48
48
  */
49
49
  export function initContext(overrides?: {
50
- persistableState?: AvmPersistableStateManager;
50
+ persistableState?: PublicPersistableStateManager;
51
51
  env?: AvmExecutionEnvironment;
52
52
  machineState?: AvmMachineState;
53
53
  }): AvmContext {
@@ -70,9 +70,9 @@ export function initPersistableStateManager(overrides?: {
70
70
  doMerkleOperations?: boolean;
71
71
  firstNullifier?: Fr;
72
72
  blockNumber?: number;
73
- }): AvmPersistableStateManager {
73
+ }): PublicPersistableStateManager {
74
74
  const treesDB = overrides?.treesDB || mock<PublicTreesDB>();
75
- return new AvmPersistableStateManager(
75
+ return new PublicPersistableStateManager(
76
76
  treesDB,
77
77
  overrides?.contractsDB || mock<PublicContractsDB>(),
78
78
  overrides?.trace || mock<PublicSideEffectTraceInterface>(),
@@ -4,7 +4,7 @@ import type { ContractArtifact, FunctionSelector } from '@aztec/stdlib/abi';
4
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
5
  import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
6
6
 
7
- import { PUBLIC_DISPATCH_FN_NAME } from './index.js';
7
+ import { getFunctionSelector } from './index.js';
8
8
 
9
9
  /**
10
10
  * This class is used during public/avm testing to function as a database of
@@ -22,6 +22,8 @@ export class SimpleContractDataSource implements ContractDataSource {
22
22
  private contractInstances: Map<string, ContractInstanceWithAddress> = new Map();
23
23
  // maps contract instance address to address
24
24
  private contractArtifacts: Map<string, ContractArtifact> = new Map();
25
+ // maps `${classID}:${fnSelector}` to name
26
+ private debugFunctionName: Map<string, string> = new Map();
25
27
 
26
28
  /////////////////////////////////////////////////////////////
27
29
  // Helper functions not in the contract data source interface
@@ -34,13 +36,25 @@ export class SimpleContractDataSource implements ContractDataSource {
34
36
  contractClass: ContractClassPublic,
35
37
  contractInstance: ContractInstanceWithAddress,
36
38
  ) {
37
- this.addContractArtifact(contractClass.id, contractArtifact);
39
+ await this.addContractArtifact(contractClass.id, contractArtifact);
38
40
  await this.addContractClass(contractClass);
39
41
  await this.addContractInstance(contractInstance);
40
42
  }
41
43
 
42
- addContractArtifact(classId: Fr, artifact: ContractArtifact): void {
44
+ async addContractArtifact(classId: Fr, artifact: ContractArtifact) {
43
45
  this.contractArtifacts.set(classId.toString(), artifact);
46
+ const classIdStr = classId.toString();
47
+ const publicFns = artifact.nonDispatchPublicFunctions;
48
+ if (publicFns.length !== 0) {
49
+ for (const fn of publicFns) {
50
+ const actualFnName = `${fn.name}`;
51
+ const fnSelector = await getFunctionSelector(actualFnName, artifact);
52
+ const key = `${classIdStr}:${fnSelector.toString()}`;
53
+
54
+ const longFnName = `${artifact.name}.${actualFnName}`;
55
+ this.debugFunctionName.set(key, longFnName);
56
+ }
57
+ }
44
58
  }
45
59
 
46
60
  /////////////////////////////////////////////////////////////
@@ -73,11 +87,24 @@ export class SimpleContractDataSource implements ContractDataSource {
73
87
  }
74
88
  this.logger.debug(`Retrieved contract artifact for address: ${address}`);
75
89
  this.logger.debug(`Contract class ID: ${contractInstance.currentContractClassId}`);
76
- return Promise.resolve(this.contractArtifacts.get(contractInstance!.currentContractClassId.toString()));
90
+ return this.contractArtifacts.get(contractInstance!.currentContractClassId.toString());
77
91
  }
78
92
 
79
- getDebugFunctionName(_address: AztecAddress, _selector: FunctionSelector): Promise<string> {
80
- return Promise.resolve(PUBLIC_DISPATCH_FN_NAME);
93
+ async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string> {
94
+ const contractInstance = await this.getContract(address);
95
+ if (!contractInstance) {
96
+ this.logger.warn(
97
+ `Couldn't get fn name for debugging. Contract not in tester's ContractDataSource. Using selector:${selector} instead...`,
98
+ );
99
+ return `selector:${selector.toString()}`;
100
+ }
101
+ const key = `${contractInstance.currentContractClassId.toString()}:${selector.toString()}`;
102
+ const fnName = this.debugFunctionName.get(key);
103
+ if (!fnName) {
104
+ this.logger.warn(`Couldn't get fn name for debugging. Using selector:${selector} instead...`);
105
+ return selector.toString();
106
+ }
107
+ return fnName;
81
108
  }
82
109
 
83
110
  registerContractFunctionSignatures(_address: AztecAddress, _signatures: string[]): Promise<void> {
@@ -1,3 +1,2 @@
1
1
  export * from './avm_simulator.js';
2
- export * from './journal/index.js';
3
2
  export * from './fixtures/simple_contract_data_source.js';
@@ -1,7 +1,7 @@
1
+ import { NullifierCollisionError } from '../../state_manager/nullifiers.js';
1
2
  import type { AvmContext } from '../avm_context.js';
2
3
  import { TypeTag, Uint1 } from '../avm_memory_types.js';
3
4
  import { InstructionExecutionError, StaticCallAlterationError } from '../errors.js';
4
- import { NullifierCollisionError } from '../journal/nullifiers.js';
5
5
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
6
6
  import { Addressing } from './addressing_mode.js';
7
7
  import { Instruction } from './instruction.js';
@@ -70,6 +70,9 @@ abstract class ExternalCall extends Instruction {
70
70
  // Track the success status directly
71
71
  context.machineState.nestedCallSuccess = success;
72
72
 
73
+ // Account for all instructions executed in the nested call
74
+ context.machineState.instrCounter += nestedCallResults.totalInstructions;
75
+
73
76
  // If the nested call reverted, we try to save the reason and the revert data.
74
77
  // This will be used by the caller to try to reconstruct the call stack.
75
78
  // This is only a heuristic and may not always work. It is intended to work
@@ -13,42 +13,42 @@ export class Set extends Instruction {
13
13
  OperandType.UINT8, // opcode
14
14
  OperandType.UINT8, // indirect
15
15
  OperandType.UINT8, // dstOffset
16
- OperandType.UINT8, // tag
16
+ OperandType.TAG, // tag
17
17
  OperandType.UINT8, // const (value)
18
18
  ];
19
19
  public static readonly wireFormat16: OperandType[] = [
20
20
  OperandType.UINT8, // opcode
21
21
  OperandType.UINT8, // indirect
22
22
  OperandType.UINT16, // dstOffset
23
- OperandType.UINT8, // tag
23
+ OperandType.TAG, // tag
24
24
  OperandType.UINT16, // const (value)
25
25
  ];
26
26
  public static readonly wireFormat32: OperandType[] = [
27
27
  OperandType.UINT8, // opcode
28
28
  OperandType.UINT8, // indirect
29
29
  OperandType.UINT16, // dstOffset
30
- OperandType.UINT8, // tag
30
+ OperandType.TAG, // tag
31
31
  OperandType.UINT32, // const (value)
32
32
  ];
33
33
  public static readonly wireFormat64: OperandType[] = [
34
34
  OperandType.UINT8, // opcode
35
35
  OperandType.UINT8, // indirect
36
36
  OperandType.UINT16, // dstOffset
37
- OperandType.UINT8, // tag
37
+ OperandType.TAG, // tag
38
38
  OperandType.UINT64, // const (value)
39
39
  ];
40
40
  public static readonly wireFormat128: OperandType[] = [
41
41
  OperandType.UINT8, // opcode
42
42
  OperandType.UINT8, // indirect
43
43
  OperandType.UINT16, // dstOffset
44
- OperandType.UINT8, // tag
44
+ OperandType.TAG, // tag
45
45
  OperandType.UINT128, // const (value)
46
46
  ];
47
47
  public static readonly wireFormatFF: OperandType[] = [
48
48
  OperandType.UINT8, // opcode
49
49
  OperandType.UINT8, // indirect
50
50
  OperandType.UINT16, // dstOffset
51
- OperandType.UINT8, // tag
51
+ OperandType.TAG, // tag
52
52
  OperandType.FF, // const (value)
53
53
  ];
54
54
 
@@ -59,7 +59,6 @@ export class Set extends Instruction {
59
59
  private value: bigint | number,
60
60
  ) {
61
61
  super();
62
- TaggedMemory.checkIsValidTag(inTag);
63
62
  }
64
63
 
65
64
  public async execute(context: AvmContext): Promise<void> {
@@ -85,19 +84,18 @@ export class Cast extends Instruction {
85
84
  OperandType.UINT8,
86
85
  OperandType.UINT8,
87
86
  OperandType.UINT8,
88
- OperandType.UINT8,
87
+ OperandType.TAG,
89
88
  ];
90
89
  static readonly wireFormat16 = [
91
90
  OperandType.UINT8,
92
91
  OperandType.UINT8,
93
92
  OperandType.UINT16,
94
93
  OperandType.UINT16,
95
- OperandType.UINT8,
94
+ OperandType.TAG,
96
95
  ];
97
96
 
98
97
  constructor(private indirect: number, private srcOffset: number, private dstOffset: number, private dstTag: number) {
99
98
  super();
100
- TaggedMemory.checkIsValidTag(dstTag);
101
99
  }
102
100
 
103
101
  public async execute(context: AvmContext): Promise<void> {
@@ -1,5 +1,6 @@
1
1
  import { strict as assert } from 'assert';
2
2
 
3
+ import { TaggedMemory } from '../avm_memory_types.js';
3
4
  import { BufferCursor } from './buffer_cursor.js';
4
5
 
5
6
  /**
@@ -92,10 +93,8 @@ export const MAX_OPCODE_VALUE = Math.max(
92
93
  .filter(k => !isNaN(k)),
93
94
  );
94
95
 
95
- // Possible types for an instruction's operand in its wire format. (Keep in sync with CPP code.
96
- // See vm/avm_trace/deserialization.cpp)
97
- // Note that cpp code introduced an additional enum value TAG to express the instruction tag. In TS,
98
- // this one is parsed as UINT8.
96
+ // Possible types for an instruction's operand in its wire format.
97
+ // The counterpart cpp file is: vm2/simulation/lib/serialization.hpp.
99
98
  export enum OperandType {
100
99
  UINT8,
101
100
  UINT16,
@@ -103,8 +102,12 @@ export enum OperandType {
103
102
  UINT64,
104
103
  UINT128,
105
104
  FF,
105
+ TAG,
106
106
  }
107
107
 
108
+ // Define a type that represents the possible types of the deserialized values.
109
+ type DeserializedValue = number | bigint;
110
+
108
111
  type OperandNativeType = number | bigint;
109
112
  type OperandWriter = (value: any) => void;
110
113
 
@@ -116,6 +119,7 @@ const OPERAND_SPEC = new Map<OperandType, [number, (offset: number) => OperandNa
116
119
  [OperandType.UINT64, [8, Buffer.prototype.readBigInt64BE, Buffer.prototype.writeBigInt64BE]],
117
120
  [OperandType.UINT128, [16, readBigInt128BE, writeBigInt128BE]],
118
121
  [OperandType.FF, [32, readBigInt254BE, writeBigInt254BE]],
122
+ [OperandType.TAG, [1, Buffer.prototype.readUint8, Buffer.prototype.writeUint8]],
119
123
  ]);
120
124
 
121
125
  function readBigInt254BE(this: Buffer, offset: number): bigint {
@@ -160,19 +164,30 @@ function writeBigInt128BE(this: Buffer, value: bigint): void {
160
164
  * @param operands Specification of the operand types.
161
165
  * @returns An array as big as {@code operands}, with the converted TS values.
162
166
  */
163
- export function deserialize(cursor: BufferCursor | Buffer, operands: OperandType[]): (number | bigint)[] {
164
- const argValues = [];
167
+ export function deserialize(cursor: BufferCursor | Buffer, operands: OperandType[]): DeserializedValue[] {
168
+ const argValues: DeserializedValue[] = [];
165
169
  if (Buffer.isBuffer(cursor)) {
166
170
  cursor = new BufferCursor(cursor);
167
171
  }
168
172
 
169
- for (const op of operands) {
170
- const opType = op;
173
+ for (const opType of operands) {
171
174
  const [sizeBytes, reader, _writer] = OPERAND_SPEC.get(opType)!;
172
- argValues.push(reader.call(cursor.buffer(), cursor.position()));
175
+ const value = reader.call(cursor.buffer(), cursor.position());
176
+ argValues.push(value);
173
177
  cursor.advance(sizeBytes);
174
178
  }
175
179
 
180
+ // We first want to detect other parsing errors (e.g., instruction size
181
+ // is longer than remaining bytes) first and therefore tag validation is done after completion
182
+ // of parsing above. Order of errors need to match with circuit.
183
+ for (let i = 0; i < operands.length; i++) {
184
+ if (operands[i] === OperandType.TAG) {
185
+ // We parsed a single byte (readUInt8()) and therefore value is of number type (not bigint)
186
+ // We need to cast to number because checkIsValidTag expects a number.
187
+ TaggedMemory.checkIsValidTag(Number(argValues[i] ?? 0));
188
+ }
189
+ }
190
+
176
191
  return argValues;
177
192
  }
178
193
 
@@ -4,7 +4,7 @@ import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/st
4
4
  import type { jest } from '@jest/globals';
5
5
  import { mock } from 'jest-mock-extended';
6
6
 
7
- import type { PublicContractsDB, PublicTreesDB } from '../../public/public_db_sources.js';
7
+ import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
8
8
  import type { PublicSideEffectTraceInterface } from '../side_effect_trace_interface.js';
9
9
 
10
10
  export function mockTraceFork(trace: PublicSideEffectTraceInterface, nestedTrace?: PublicSideEffectTraceInterface) {
@@ -1,3 +1,4 @@
1
+ import type { RevertCode } from '@aztec/stdlib/avm';
1
2
  import {
2
3
  Attributes,
3
4
  type Histogram,
@@ -8,11 +9,16 @@ import {
8
9
  ValueType,
9
10
  } from '@aztec/telemetry-client';
10
11
 
11
- export class ExecutorMetrics {
12
+ import type { ExecutorMetricsInterface } from './executor_metrics_interface.js';
13
+
14
+ export class ExecutorMetrics implements ExecutorMetricsInterface {
12
15
  public readonly tracer: Tracer;
13
16
  private fnCount: UpDownCounter;
14
17
  private fnDuration: Histogram;
15
18
  private manaPerSecond: Histogram;
19
+ private manaUsed: Histogram;
20
+ private totalInstructions: Histogram;
21
+ private txHashing: Histogram;
16
22
  private privateEffectsInsertions: Histogram;
17
23
 
18
24
  constructor(client: TelemetryClient, name = 'PublicExecutor') {
@@ -35,20 +41,53 @@ export class ExecutorMetrics {
35
41
  valueType: ValueType.INT,
36
42
  });
37
43
 
38
- this.privateEffectsInsertions = meter.createHistogram(Metrics.PUBLIC_EXECUTION_PRIVATE_EFFECTS_INSERTION, {
44
+ this.manaUsed = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_MANA_USED, {
45
+ description: 'Total mana used',
46
+ unit: 'mana',
47
+ valueType: ValueType.INT,
48
+ });
49
+
50
+ this.totalInstructions = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_TOTAL_INSTRUCTIONS, {
51
+ description: 'Total number of instructions executed',
52
+ unit: 'instructions',
53
+ valueType: ValueType.INT,
54
+ });
55
+
56
+ this.txHashing = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_TX_HASHING, {
57
+ description: 'Tx hashing time',
58
+ unit: 'ms',
59
+ valueType: ValueType.INT,
60
+ });
61
+
62
+ this.privateEffectsInsertions = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_PRIVATE_EFFECTS_INSERTION, {
39
63
  description: 'Private effects insertion time',
40
64
  unit: 'us',
41
65
  valueType: ValueType.INT,
42
66
  });
43
67
  }
44
68
 
45
- recordFunctionSimulation(durationMs: number, manaUsed: number, fnName: string) {
69
+ startRecordingTxSimulation(_txLabel: string) {
70
+ // do nothing (unimplemented)
71
+ }
72
+
73
+ stopRecordingTxSimulation(_txLabel: string, _revertedCode?: RevertCode) {
74
+ // do nothing (unimplemented)
75
+ }
76
+
77
+ recordEnqueuedCallSimulation(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number) {
46
78
  this.fnCount.add(1, {
47
79
  [Attributes.OK]: true,
48
80
  [Attributes.APP_CIRCUIT_NAME]: fnName,
49
- [Attributes.MANA_USED]: manaUsed,
50
81
  });
51
- this.fnDuration.record(Math.ceil(durationMs));
82
+ this.manaUsed.record(Math.ceil(manaUsed), {
83
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
84
+ });
85
+ this.totalInstructions.record(Math.ceil(totalInstructions), {
86
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
87
+ });
88
+ this.fnDuration.record(Math.ceil(durationMs), {
89
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
90
+ });
52
91
  if (durationMs > 0 && manaUsed > 0) {
53
92
  const manaPerSecond = Math.round((manaUsed * 1000) / durationMs);
54
93
  this.manaPerSecond.record(manaPerSecond, {
@@ -57,12 +96,21 @@ export class ExecutorMetrics {
57
96
  }
58
97
  }
59
98
 
60
- recordFunctionSimulationFailure() {
99
+ recordEnqueuedCallSimulationFailure(
100
+ _fnName: string,
101
+ _durationMs: number,
102
+ _manaUsed: number,
103
+ _totalInstructions: number,
104
+ ) {
61
105
  this.fnCount.add(1, {
62
106
  [Attributes.OK]: false,
63
107
  });
64
108
  }
65
109
 
110
+ recordTxHashComputation(durationMs: number) {
111
+ this.txHashing.record(Math.ceil(durationMs));
112
+ }
113
+
66
114
  recordPrivateEffectsInsertion(durationUs: number, type: 'revertible' | 'non-revertible') {
67
115
  this.privateEffectsInsertions.record(Math.ceil(durationUs), {
68
116
  [Attributes.REVERTIBILITY]: type,
@@ -0,0 +1,15 @@
1
+ import type { RevertCode } from '@aztec/stdlib/avm';
2
+
3
+ export interface ExecutorMetricsInterface {
4
+ startRecordingTxSimulation(txLabel: string): void;
5
+ stopRecordingTxSimulation(txLabel: string, revertedCode?: RevertCode): void;
6
+ recordEnqueuedCallSimulation(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number): void;
7
+ recordEnqueuedCallSimulationFailure(
8
+ fnName: string,
9
+ durationMs: number,
10
+ manaUsed: number,
11
+ totalInstructions: number,
12
+ ): void;
13
+ recordTxHashComputation(durationMs: number): void;
14
+ recordPrivateEffectsInsertion(durationUs: number, type: 'revertible' | 'non-revertible'): void;
15
+ }
@@ -9,17 +9,19 @@ import { GlobalVariables, PublicCallRequestWithCalldata, type Tx } from '@aztec/
9
9
  import { NativeWorldStateService } from '@aztec/world-state';
10
10
 
11
11
  import { BaseAvmSimulationTester } from '../avm/fixtures/base_avm_simulation_tester.js';
12
- import { getContractFunctionAbi, getFunctionSelector } from '../avm/fixtures/index.js';
12
+ import { DEFAULT_BLOCK_NUMBER, getContractFunctionAbi, getFunctionSelector } from '../avm/fixtures/index.js';
13
13
  import { SimpleContractDataSource } from '../avm/fixtures/simple_contract_data_source.js';
14
14
  import { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
15
- import { type PublicTxResult, PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
15
+ import { MeasuredPublicTxSimulator } from '../public_tx_simulator/measured_public_tx_simulator.js';
16
+ import type { PublicTxResult } from '../public_tx_simulator/public_tx_simulator.js';
17
+ import { TestExecutorMetrics } from '../test_executor_metrics.js';
16
18
  import { createTxForPublicCalls } from './utils.js';
17
19
 
18
20
  const TIMESTAMP = new Fr(99833);
19
21
  const DEFAULT_GAS_FEES = new GasFees(2, 3);
20
- export const DEFAULT_BLOCK_NUMBER = 42;
21
22
 
22
23
  export type TestEnqueuedCall = {
24
+ sender?: AztecAddress;
23
25
  address: AztecAddress;
24
26
  fnName: string;
25
27
  args: any[];
@@ -34,15 +36,41 @@ export type TestEnqueuedCall = {
34
36
  */
35
37
  export class PublicTxSimulationTester extends BaseAvmSimulationTester {
36
38
  private txCount = 0;
37
-
38
- constructor(private merkleTree: MerkleTreeWriteOperations, contractDataSource: SimpleContractDataSource) {
39
+ private simulator: MeasuredPublicTxSimulator;
40
+ private metricsPrefix?: string;
41
+
42
+ constructor(
43
+ merkleTree: MerkleTreeWriteOperations,
44
+ contractDataSource: SimpleContractDataSource,
45
+ globals: GlobalVariables = defaultGlobals(),
46
+ private metrics: TestExecutorMetrics = new TestExecutorMetrics(),
47
+ ) {
39
48
  super(contractDataSource, merkleTree);
49
+
50
+ const treesDB = new PublicTreesDB(merkleTree);
51
+ const contractsDB = new PublicContractsDB(contractDataSource);
52
+
53
+ this.simulator = new MeasuredPublicTxSimulator(
54
+ treesDB,
55
+ contractsDB,
56
+ globals,
57
+ /*doMerkleOperations=*/ true,
58
+ /*skipFeeEnforcement=*/ false,
59
+ this.metrics,
60
+ );
40
61
  }
41
62
 
42
- public static async create(): Promise<PublicTxSimulationTester> {
63
+ public static async create(
64
+ globals: GlobalVariables = defaultGlobals(),
65
+ metrics: TestExecutorMetrics = new TestExecutorMetrics(),
66
+ ): Promise<PublicTxSimulationTester> {
43
67
  const contractDataSource = new SimpleContractDataSource();
44
68
  const merkleTree = await (await NativeWorldStateService.tmp()).fork();
45
- return new PublicTxSimulationTester(merkleTree, contractDataSource);
69
+ return new PublicTxSimulationTester(merkleTree, contractDataSource, globals, metrics);
70
+ }
71
+
72
+ public setMetricsPrefix(prefix: string) {
73
+ this.metricsPrefix = prefix;
46
74
  }
47
75
 
48
76
  public async createTx(
@@ -54,10 +82,14 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
54
82
  /* need some unique first nullifier for note-nonce computations */
55
83
  firstNullifier = new Fr(420000 + this.txCount++),
56
84
  ): Promise<Tx> {
57
- const setupCallRequests = await asyncMap(setupCalls, call => this.#createPubicCallRequestForCall(call, sender));
58
- const appCallRequests = await asyncMap(appCalls, call => this.#createPubicCallRequestForCall(call, sender));
85
+ const setupCallRequests = await asyncMap(setupCalls, call =>
86
+ this.#createPubicCallRequestForCall(call, call.sender ?? sender),
87
+ );
88
+ const appCallRequests = await asyncMap(appCalls, call =>
89
+ this.#createPubicCallRequestForCall(call, call.sender ?? sender),
90
+ );
59
91
  const teardownCallRequest = teardownCall
60
- ? await this.#createPubicCallRequestForCall(teardownCall, sender)
92
+ ? await this.#createPubicCallRequestForCall(teardownCall, teardownCall.sender ?? sender)
61
93
  : undefined;
62
94
 
63
95
  return createTxForPublicCalls(firstNullifier, setupCallRequests, appCallRequests, teardownCallRequest, feePayer);
@@ -71,24 +103,48 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
71
103
  feePayer: AztecAddress = sender,
72
104
  /* need some unique first nullifier for note-nonce computations */
73
105
  firstNullifier = new Fr(420000 + this.txCount++),
74
- globals = defaultGlobals(),
106
+ txLabel: string = 'unlabeledTx',
75
107
  ): Promise<PublicTxResult> {
76
108
  const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, firstNullifier);
77
109
 
78
110
  await this.setFeePayerBalance(feePayer);
79
111
 
80
- const treesDB = new PublicTreesDB(this.merkleTree);
81
- const contractsDB = new PublicContractsDB(this.contractDataSource);
82
- const simulator = new PublicTxSimulator(treesDB, contractsDB, globals, /*doMerkleOperations=*/ true);
112
+ const txLabelWithCount = `${txLabel}.${this.txCount - 1}`;
113
+ const fullTxLabel = this.metricsPrefix ? `${this.metricsPrefix}.${txLabelWithCount}` : txLabelWithCount;
83
114
 
84
- const startTime = performance.now();
85
- const avmResult = await simulator.simulate(tx);
86
- const endTime = performance.now();
87
- this.logger.debug(`Public transaction simulation took ${endTime - startTime}ms`);
115
+ const avmResult = await this.simulator.simulate(tx, fullTxLabel);
116
+
117
+ // Something like this is often useful for debugging:
118
+ //if (avmResult.revertReason) {
119
+ // // resolve / enrich revert reason
120
+ // const lastAppCall = appCalls[appCalls.length - 1];
121
+
122
+ // const contractArtifact =
123
+ // lastAppCall.contractArtifact || (await this.contractDataSource.getContractArtifact(lastAppCall.address));
124
+ // const fnAbi = getContractFunctionAbi(lastAppCall.fnName, contractArtifact!);
125
+ // const revertReason = resolveAssertionMessageFromRevertData(avmResult.revertReason.revertData, fnAbi!);
126
+ // this.logger.debug(`Revert reason: ${revertReason}`);
127
+ //}
88
128
 
89
129
  return avmResult;
90
130
  }
91
131
 
132
+ public async simulateTxWithLabel(
133
+ txLabel: string,
134
+ sender: AztecAddress,
135
+ setupCalls?: TestEnqueuedCall[],
136
+ appCalls?: TestEnqueuedCall[],
137
+ teardownCall?: TestEnqueuedCall,
138
+ feePayer?: AztecAddress,
139
+ firstNullifier?: Fr,
140
+ ): Promise<PublicTxResult> {
141
+ return await this.simulateTx(sender, setupCalls, appCalls, teardownCall, feePayer, firstNullifier, txLabel);
142
+ }
143
+
144
+ public prettyPrintMetrics() {
145
+ this.metrics.prettyPrint();
146
+ }
147
+
92
148
  async #createPubicCallRequestForCall(
93
149
  call: TestEnqueuedCall,
94
150
  sender: AztecAddress,