@aztec/simulator 0.59.0 → 0.61.0

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 (190) hide show
  1. package/dest/acvm/acvm.d.ts +1 -0
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.d.ts +5 -3
  4. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  5. package/dest/acvm/oracle/oracle.js +15 -7
  6. package/dest/acvm/oracle/typed_oracle.d.ts +7 -4
  7. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  8. package/dest/acvm/oracle/typed_oracle.js +10 -4
  9. package/dest/acvm/serialize.d.ts +1 -0
  10. package/dest/acvm/serialize.d.ts.map +1 -1
  11. package/dest/avm/avm_context.d.ts +1 -1
  12. package/dest/avm/avm_context.js +1 -1
  13. package/dest/avm/avm_execution_environment.d.ts +2 -5
  14. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  15. package/dest/avm/avm_execution_environment.js +7 -15
  16. package/dest/avm/avm_gas.d.ts.map +1 -1
  17. package/dest/avm/avm_gas.js +6 -10
  18. package/dest/avm/avm_machine_state.d.ts +2 -0
  19. package/dest/avm/avm_machine_state.d.ts.map +1 -1
  20. package/dest/avm/avm_machine_state.js +3 -1
  21. package/dest/avm/avm_memory_types.d.ts +1 -0
  22. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  23. package/dest/avm/avm_simulator.d.ts +16 -0
  24. package/dest/avm/avm_simulator.d.ts.map +1 -1
  25. package/dest/avm/avm_simulator.js +45 -4
  26. package/dest/avm/bytecode_utils.d.ts +1 -0
  27. package/dest/avm/bytecode_utils.d.ts.map +1 -1
  28. package/dest/avm/fixtures/index.d.ts +3 -0
  29. package/dest/avm/fixtures/index.d.ts.map +1 -1
  30. package/dest/avm/fixtures/index.js +8 -2
  31. package/dest/avm/journal/journal.d.ts +19 -19
  32. package/dest/avm/journal/journal.d.ts.map +1 -1
  33. package/dest/avm/journal/journal.js +73 -48
  34. package/dest/avm/journal/nullifiers.d.ts +9 -9
  35. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  36. package/dest/avm/journal/nullifiers.js +24 -24
  37. package/dest/avm/journal/public_storage.d.ts +10 -10
  38. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  39. package/dest/avm/journal/public_storage.js +21 -21
  40. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  41. package/dest/avm/opcodes/accrued_substate.js +5 -5
  42. package/dest/avm/opcodes/contract.d.ts +8 -1
  43. package/dest/avm/opcodes/contract.d.ts.map +1 -1
  44. package/dest/avm/opcodes/contract.js +41 -21
  45. package/dest/avm/opcodes/conversion.d.ts +1 -1
  46. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  47. package/dest/avm/opcodes/conversion.js +12 -9
  48. package/dest/avm/opcodes/environment_getters.d.ts +13 -14
  49. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  50. package/dest/avm/opcodes/environment_getters.js +17 -16
  51. package/dest/avm/opcodes/external_calls.d.ts +3 -6
  52. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  53. package/dest/avm/opcodes/external_calls.js +23 -43
  54. package/dest/avm/opcodes/hashing.d.ts +2 -26
  55. package/dest/avm/opcodes/hashing.d.ts.map +1 -1
  56. package/dest/avm/opcodes/hashing.js +11 -95
  57. package/dest/avm/opcodes/index.d.ts +0 -1
  58. package/dest/avm/opcodes/index.d.ts.map +1 -1
  59. package/dest/avm/opcodes/index.js +1 -2
  60. package/dest/avm/opcodes/instruction.d.ts +1 -0
  61. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  62. package/dest/avm/opcodes/memory.d.ts +20 -0
  63. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  64. package/dest/avm/opcodes/memory.js +59 -3
  65. package/dest/avm/opcodes/storage.js +3 -3
  66. package/dest/avm/serialization/buffer_cursor.d.ts +1 -0
  67. package/dest/avm/serialization/buffer_cursor.d.ts.map +1 -1
  68. package/dest/avm/serialization/bytecode_serialization.d.ts +1 -0
  69. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  70. package/dest/avm/serialization/bytecode_serialization.js +5 -7
  71. package/dest/avm/serialization/instruction_serialization.d.ts +34 -35
  72. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  73. package/dest/avm/serialization/instruction_serialization.js +34 -36
  74. package/dest/avm/test_utils.d.ts +3 -1
  75. package/dest/avm/test_utils.d.ts.map +1 -1
  76. package/dest/avm/test_utils.js +4 -1
  77. package/dest/client/client_execution_context.d.ts +9 -18
  78. package/dest/client/client_execution_context.d.ts.map +1 -1
  79. package/dest/client/client_execution_context.js +30 -50
  80. package/dest/client/db_oracle.d.ts +17 -1
  81. package/dest/client/db_oracle.d.ts.map +1 -1
  82. package/dest/client/db_oracle.js +1 -1
  83. package/dest/client/private_execution.d.ts.map +1 -1
  84. package/dest/client/private_execution.js +3 -4
  85. package/dest/client/simulator.d.ts.map +1 -1
  86. package/dest/client/simulator.js +3 -3
  87. package/dest/client/view_data_oracle.d.ts +17 -1
  88. package/dest/client/view_data_oracle.d.ts.map +1 -1
  89. package/dest/client/view_data_oracle.js +21 -1
  90. package/dest/common/index.d.ts +0 -1
  91. package/dest/common/index.d.ts.map +1 -1
  92. package/dest/common/index.js +1 -2
  93. package/dest/mocks/fixtures.js +2 -2
  94. package/dest/providers/acvm_native.d.ts +1 -0
  95. package/dest/providers/acvm_native.d.ts.map +1 -1
  96. package/dest/public/db_interfaces.d.ts +1 -0
  97. package/dest/public/db_interfaces.d.ts.map +1 -1
  98. package/dest/public/dual_side_effect_trace.d.ts +10 -11
  99. package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
  100. package/dest/public/dual_side_effect_trace.js +26 -22
  101. package/dest/public/enqueued_call_side_effect_trace.d.ts +11 -12
  102. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  103. package/dest/public/enqueued_call_side_effect_trace.js +33 -23
  104. package/dest/public/enqueued_call_simulator.d.ts +3 -3
  105. package/dest/public/enqueued_call_simulator.d.ts.map +1 -1
  106. package/dest/public/enqueued_call_simulator.js +30 -39
  107. package/dest/public/enqueued_calls_processor.d.ts +2 -3
  108. package/dest/public/enqueued_calls_processor.d.ts.map +1 -1
  109. package/dest/public/enqueued_calls_processor.js +19 -26
  110. package/dest/public/execution.d.ts +1 -0
  111. package/dest/public/execution.d.ts.map +1 -1
  112. package/dest/public/execution.js +2 -2
  113. package/dest/public/executor.d.ts.map +1 -1
  114. package/dest/public/executor.js +6 -5
  115. package/dest/public/public_db_sources.d.ts +1 -0
  116. package/dest/public/public_db_sources.d.ts.map +1 -1
  117. package/dest/public/public_kernel.d.ts +0 -1
  118. package/dest/public/public_kernel.d.ts.map +1 -1
  119. package/dest/public/public_kernel.js +5 -8
  120. package/dest/public/public_kernel_tail_simulator.d.ts +1 -5
  121. package/dest/public/public_kernel_tail_simulator.d.ts.map +1 -1
  122. package/dest/public/public_kernel_tail_simulator.js +6 -12
  123. package/dest/public/public_processor.js +4 -4
  124. package/dest/public/side_effect_trace.d.ts +11 -9
  125. package/dest/public/side_effect_trace.d.ts.map +1 -1
  126. package/dest/public/side_effect_trace.js +40 -30
  127. package/dest/public/side_effect_trace_interface.d.ts +10 -9
  128. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  129. package/package.json +9 -9
  130. package/src/acvm/oracle/oracle.ts +13 -6
  131. package/src/acvm/oracle/typed_oracle.ts +9 -3
  132. package/src/avm/avm_context.ts +1 -1
  133. package/src/avm/avm_execution_environment.ts +0 -15
  134. package/src/avm/avm_gas.ts +5 -9
  135. package/src/avm/avm_machine_state.ts +2 -0
  136. package/src/avm/avm_simulator.ts +69 -6
  137. package/src/avm/fixtures/index.ts +7 -2
  138. package/src/avm/journal/journal.ts +93 -50
  139. package/src/avm/journal/nullifiers.ts +23 -23
  140. package/src/avm/journal/public_storage.ts +20 -20
  141. package/src/avm/opcodes/accrued_substate.ts +4 -8
  142. package/src/avm/opcodes/contract.ts +45 -21
  143. package/src/avm/opcodes/conversion.ts +9 -6
  144. package/src/avm/opcodes/environment_getters.ts +7 -5
  145. package/src/avm/opcodes/external_calls.ts +21 -45
  146. package/src/avm/opcodes/hashing.ts +9 -122
  147. package/src/avm/opcodes/index.ts +0 -1
  148. package/src/avm/opcodes/memory.ts +69 -2
  149. package/src/avm/opcodes/storage.ts +2 -2
  150. package/src/avm/serialization/bytecode_serialization.ts +6 -9
  151. package/src/avm/serialization/instruction_serialization.ts +3 -5
  152. package/src/avm/test_utils.ts +5 -1
  153. package/src/client/client_execution_context.ts +21 -71
  154. package/src/client/db_oracle.ts +26 -0
  155. package/src/client/private_execution.ts +1 -9
  156. package/src/client/simulator.ts +0 -2
  157. package/src/client/view_data_oracle.ts +31 -1
  158. package/src/common/index.ts +0 -1
  159. package/src/mocks/fixtures.ts +1 -1
  160. package/src/public/dual_side_effect_trace.ts +38 -24
  161. package/src/public/enqueued_call_side_effect_trace.ts +60 -28
  162. package/src/public/enqueued_call_simulator.ts +52 -49
  163. package/src/public/enqueued_calls_processor.ts +27 -41
  164. package/src/public/execution.ts +1 -1
  165. package/src/public/executor.ts +11 -5
  166. package/src/public/public_kernel.ts +9 -12
  167. package/src/public/public_kernel_tail_simulator.ts +6 -15
  168. package/src/public/public_processor.ts +3 -3
  169. package/src/public/side_effect_trace.ts +73 -29
  170. package/src/public/side_effect_trace_interface.ts +15 -10
  171. package/dest/avm/opcodes/commitment.d.ts +0 -16
  172. package/dest/avm/opcodes/commitment.d.ts.map +0 -1
  173. package/dest/avm/opcodes/commitment.js +0 -51
  174. package/dest/client/test_utils.d.ts +0 -9
  175. package/dest/client/test_utils.d.ts.map +0 -1
  176. package/dest/client/test_utils.js +0 -27
  177. package/dest/common/side_effect_counter.d.ts +0 -10
  178. package/dest/common/side_effect_counter.d.ts.map +0 -1
  179. package/dest/common/side_effect_counter.js +0 -18
  180. package/dest/rollup/index.d.ts +0 -2
  181. package/dest/rollup/index.d.ts.map +0 -1
  182. package/dest/rollup/index.js +0 -2
  183. package/dest/rollup/rollup.d.ts +0 -101
  184. package/dest/rollup/rollup.d.ts.map +0 -1
  185. package/dest/rollup/rollup.js +0 -100
  186. package/src/avm/opcodes/commitment.ts +0 -65
  187. package/src/client/test_utils.ts +0 -57
  188. package/src/common/side_effect_counter.ts +0 -17
  189. package/src/rollup/index.ts +0 -1
  190. package/src/rollup/rollup.ts +0 -228
@@ -6,6 +6,7 @@ import { strict as assert } from 'assert';
6
6
  import { SideEffectLimitReachedError } from '../public/side_effect_errors.js';
7
7
  import type { AvmContext } from './avm_context.js';
8
8
  import { AvmContractCallResult } from './avm_contract_call_result.js';
9
+ import { type Gas } from './avm_gas.js';
9
10
  import { isAvmBytecode } from './bytecode_utils.js';
10
11
  import {
11
12
  AvmExecutionError,
@@ -17,9 +18,21 @@ import {
17
18
  import type { Instruction } from './opcodes/index.js';
18
19
  import { decodeFromBytecode } from './serialization/bytecode_serialization.js';
19
20
 
21
+ type OpcodeTally = {
22
+ count: number;
23
+ gas: Gas;
24
+ };
25
+ type PcTally = {
26
+ opcode: string;
27
+ count: number;
28
+ gas: Gas;
29
+ };
30
+
20
31
  export class AvmSimulator {
21
32
  private log: DebugLogger;
22
33
  private bytecode: Buffer | undefined;
34
+ public opcodeTallies: Map<string, OpcodeTally> = new Map();
35
+ public pcTallies: Map<number, PcTally> = new Map();
23
36
 
24
37
  constructor(private context: AvmContext) {
25
38
  assert(
@@ -33,10 +46,7 @@ export class AvmSimulator {
33
46
  * Fetch the bytecode and execute it in the current context.
34
47
  */
35
48
  public async execute(): Promise<AvmContractCallResult> {
36
- const bytecode = await this.context.persistableState.getBytecode(
37
- this.context.environment.address,
38
- this.context.environment.functionSelector,
39
- );
49
+ const bytecode = await this.context.persistableState.getBytecode(this.context.environment.address);
40
50
 
41
51
  // This assumes that we will not be able to send messages to accounts without code
42
52
  // Pending classes and instances impl details
@@ -75,6 +85,7 @@ export class AvmSimulator {
75
85
  try {
76
86
  // Execute instruction pointed to by the current program counter
77
87
  // continuing until the machine state signifies a halt
88
+ let instrCounter = 0;
78
89
  while (!machineState.getHalted()) {
79
90
  const instruction = instructions[machineState.pc];
80
91
  assert(
@@ -82,13 +93,26 @@ export class AvmSimulator {
82
93
  'AVM attempted to execute non-existent instruction. This should never happen (invalid bytecode or AVM simulator bug)!',
83
94
  );
84
95
 
85
- const gasLeft = `l2=${machineState.l2GasLeft} da=${machineState.daGasLeft}`;
86
- this.log.debug(`@${machineState.pc} ${instruction.toString()} (${gasLeft})`);
96
+ const instrStartGas = machineState.gasLeft; // Save gas before executing instruction (for profiling)
97
+ const instrPc = machineState.pc; // Save PC before executing instruction (for profiling)
98
+
99
+ this.log.debug(
100
+ `[PC:${machineState.pc}] [IC:${instrCounter++}] ${instruction.toString()} (gasLeft l2=${
101
+ machineState.l2GasLeft
102
+ } da=${machineState.daGasLeft})`,
103
+ );
87
104
  // Execute the instruction.
88
105
  // Normal returns and reverts will return normally here.
89
106
  // "Exceptional halts" will throw.
90
107
  await instruction.execute(this.context);
91
108
 
109
+ // gas used by this instruction - used for profiling/tallying
110
+ const gasUsed: Gas = {
111
+ l2Gas: instrStartGas.l2Gas - machineState.l2GasLeft,
112
+ daGas: instrStartGas.daGas - machineState.daGasLeft,
113
+ };
114
+ this.tallyInstruction(instrPc, instruction.constructor.name, gasUsed);
115
+
92
116
  if (machineState.pc >= instructions.length) {
93
117
  this.log.warn('Passed end of program');
94
118
  throw new InvalidProgramCounterError(machineState.pc, /*max=*/ instructions.length);
@@ -100,6 +124,8 @@ export class AvmSimulator {
100
124
  const revertReason = reverted ? revertReasonFromExplicitRevert(output, this.context) : undefined;
101
125
  const results = new AvmContractCallResult(reverted, output, revertReason);
102
126
  this.log.debug(`Context execution results: ${results.toString()}`);
127
+
128
+ this.printOpcodeTallies();
103
129
  // Return results for processing by calling context
104
130
  return results;
105
131
  } catch (err: any) {
@@ -113,8 +139,45 @@ export class AvmSimulator {
113
139
  // Note: "exceptional halts" cannot return data, hence []
114
140
  const results = new AvmContractCallResult(/*reverted=*/ true, /*output=*/ [], revertReason);
115
141
  this.log.debug(`Context execution results: ${results.toString()}`);
142
+
143
+ this.printOpcodeTallies();
116
144
  // Return results for processing by calling context
117
145
  return results;
118
146
  }
119
147
  }
148
+
149
+ private tallyInstruction(pc: number, opcode: string, gasUsed: Gas) {
150
+ const opcodeTally = this.opcodeTallies.get(opcode) || ({ count: 0, gas: { l2Gas: 0, daGas: 0 } } as OpcodeTally);
151
+ opcodeTally.count++;
152
+ opcodeTally.gas.l2Gas += gasUsed.l2Gas;
153
+ opcodeTally.gas.daGas += gasUsed.daGas;
154
+ this.opcodeTallies.set(opcode, opcodeTally);
155
+
156
+ const pcTally = this.pcTallies.get(pc) || ({ opcode: opcode, count: 0, gas: { l2Gas: 0, daGas: 0 } } as PcTally);
157
+ pcTally.count++;
158
+ pcTally.gas.l2Gas += gasUsed.l2Gas;
159
+ pcTally.gas.daGas += gasUsed.daGas;
160
+ this.pcTallies.set(pc, pcTally);
161
+ }
162
+
163
+ private printOpcodeTallies() {
164
+ this.log.debug(`Printing tallies per opcode sorted by gas...`);
165
+ // sort descending by L2 gas consumed
166
+ const sortedOpcodes = Array.from(this.opcodeTallies.entries()).sort((a, b) => b[1].gas.l2Gas - a[1].gas.l2Gas);
167
+ for (const [opcode, tally] of sortedOpcodes) {
168
+ // NOTE: don't care to clutter the logs with DA gas for now
169
+ this.log.debug(`${opcode} executed ${tally.count} times consuming a total of ${tally.gas.l2Gas} L2 gas`);
170
+ }
171
+
172
+ this.log.debug(`Printing tallies per PC sorted by #times each PC was executed...`);
173
+ const sortedPcs = Array.from(this.pcTallies.entries())
174
+ .sort((a, b) => b[1].count - a[1].count)
175
+ .filter((_, i) => i < 20);
176
+ for (const [pc, tally] of sortedPcs) {
177
+ // NOTE: don't care to clutter the logs with DA gas for now
178
+ this.log.debug(
179
+ `PC:${pc} containing opcode ${tally.opcode} executed ${tally.count} times consuming a total of ${tally.gas.l2Gas} L2 gas`,
180
+ );
181
+ }
182
+ }
120
183
  }
@@ -58,14 +58,12 @@ export function initPersistableStateManager(overrides?: {
58
58
  export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnvironment>): AvmExecutionEnvironment {
59
59
  return new AvmExecutionEnvironment(
60
60
  overrides?.address ?? AztecAddress.zero(),
61
- overrides?.storageAddress ?? AztecAddress.zero(),
62
61
  overrides?.sender ?? AztecAddress.zero(),
63
62
  overrides?.functionSelector ?? FunctionSelector.empty(),
64
63
  overrides?.contractCallDepth ?? Fr.zero(),
65
64
  overrides?.transactionFee ?? Fr.zero(),
66
65
  overrides?.globals ?? GlobalVariables.empty(),
67
66
  overrides?.isStaticCall ?? false,
68
- overrides?.isDelegateCall ?? false,
69
67
  overrides?.calldata ?? [],
70
68
  );
71
69
  }
@@ -119,6 +117,13 @@ export function randomMemoryFields(length: number): Field[] {
119
117
  return [...Array(length)].map(_ => new Field(Fr.random()));
120
118
  }
121
119
 
120
+ export function getAvmTestContractFunctionSelector(functionName: string): FunctionSelector {
121
+ const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
122
+ assert(!!artifact, `Function ${functionName} not found in AvmTestContractArtifact`);
123
+ const params = artifact.parameters;
124
+ return FunctionSelector.fromNameAndParameters(artifact.name, params);
125
+ }
126
+
122
127
  export function getAvmTestContractBytecode(functionName: string): Buffer {
123
128
  const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
124
129
  assert(
@@ -1,10 +1,16 @@
1
- import { AztecAddress, type FunctionSelector, type Gas, SerializableContractInstance } from '@aztec/circuits.js';
1
+ import {
2
+ AztecAddress,
3
+ type Gas,
4
+ SerializableContractInstance,
5
+ computePublicBytecodeCommitment,
6
+ } from '@aztec/circuits.js';
2
7
  import { Fr } from '@aztec/foundation/fields';
3
8
  import { createDebugLogger } from '@aztec/foundation/log';
4
9
 
10
+ import assert from 'assert';
11
+
5
12
  import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
6
13
  import { type WorldStateDB } from '../../public/public_db_sources.js';
7
- import { type TracedContractInstance } from '../../public/side_effect_trace.js';
8
14
  import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
9
15
  import { type AvmContractCallResult } from '../avm_contract_call_result.js';
10
16
  import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
@@ -67,44 +73,44 @@ export class AvmPersistableStateManager {
67
73
  /**
68
74
  * Write to public storage, journal/trace the write.
69
75
  *
70
- * @param storageAddress - the address of the contract whose storage is being written to
76
+ * @param contractAddress - the address of the contract whose storage is being written to
71
77
  * @param slot - the slot in the contract's storage being written to
72
78
  * @param value - the value being written to the slot
73
79
  */
74
- public writeStorage(storageAddress: Fr, slot: Fr, value: Fr) {
75
- this.log.debug(`Storage write (address=${storageAddress}, slot=${slot}): value=${value}`);
80
+ public writeStorage(contractAddress: Fr, slot: Fr, value: Fr) {
81
+ this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
76
82
  // Cache storage writes for later reference/reads
77
- this.publicStorage.write(storageAddress, slot, value);
78
- this.trace.tracePublicStorageWrite(storageAddress, slot, value);
83
+ this.publicStorage.write(contractAddress, slot, value);
84
+ this.trace.tracePublicStorageWrite(contractAddress, slot, value);
79
85
  }
80
86
 
81
87
  /**
82
88
  * Read from public storage, trace the read.
83
89
  *
84
- * @param storageAddress - the address of the contract whose storage is being read from
90
+ * @param contractAddress - the address of the contract whose storage is being read from
85
91
  * @param slot - the slot in the contract's storage being read from
86
92
  * @returns the latest value written to slot, or 0 if never written to before
87
93
  */
88
- public async readStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
89
- const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
94
+ public async readStorage(contractAddress: Fr, slot: Fr): Promise<Fr> {
95
+ const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
90
96
  this.log.debug(
91
- `Storage read (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
97
+ `Storage read (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
92
98
  );
93
- this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached);
99
+ this.trace.tracePublicStorageRead(contractAddress, slot, value, exists, cached);
94
100
  return Promise.resolve(value);
95
101
  }
96
102
 
97
103
  /**
98
104
  * Read from public storage, don't trace the read.
99
105
  *
100
- * @param storageAddress - the address of the contract whose storage is being read from
106
+ * @param contractAddress - the address of the contract whose storage is being read from
101
107
  * @param slot - the slot in the contract's storage being read from
102
108
  * @returns the latest value written to slot, or 0 if never written to before
103
109
  */
104
- public async peekStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
105
- const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
110
+ public async peekStorage(contractAddress: Fr, slot: Fr): Promise<Fr> {
111
+ const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
106
112
  this.log.debug(
107
- `Storage peek (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
113
+ `Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
108
114
  );
109
115
  return Promise.resolve(value);
110
116
  }
@@ -113,20 +119,20 @@ export class AvmPersistableStateManager {
113
119
  /**
114
120
  * Check if a note hash exists at the given leaf index, trace the check.
115
121
  *
116
- * @param storageAddress - the address of the contract whose storage is being read from
122
+ * @param contractAddress - the address of the contract whose storage is being read from
117
123
  * @param noteHash - the unsiloed note hash being checked
118
124
  * @param leafIndex - the leaf index being checked
119
125
  * @returns true if the note hash exists at the given leaf index, false otherwise
120
126
  */
121
- public async checkNoteHashExists(storageAddress: Fr, noteHash: Fr, leafIndex: Fr): Promise<boolean> {
127
+ public async checkNoteHashExists(contractAddress: Fr, noteHash: Fr, leafIndex: Fr): Promise<boolean> {
122
128
  const gotLeafValue = (await this.worldStateDB.getCommitmentValue(leafIndex.toBigInt())) ?? Fr.ZERO;
123
129
  const exists = gotLeafValue.equals(noteHash);
124
130
  this.log.debug(
125
- `noteHashes(${storageAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
131
+ `noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
126
132
  );
127
133
  // TODO(8287): We still return exists here, but we need to transmit both the requested noteHash and the gotLeafValue
128
134
  // such that the VM can constrain the equality and decide on exists based on that.
129
- this.trace.traceNoteHashCheck(storageAddress, gotLeafValue, leafIndex, exists);
135
+ this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists);
130
136
  return Promise.resolve(exists);
131
137
  }
132
138
 
@@ -134,37 +140,37 @@ export class AvmPersistableStateManager {
134
140
  * Write a note hash, trace the write.
135
141
  * @param noteHash - the unsiloed note hash to write
136
142
  */
137
- public writeNoteHash(storageAddress: Fr, noteHash: Fr) {
138
- this.log.debug(`noteHashes(${storageAddress}) += @${noteHash}.`);
139
- this.trace.traceNewNoteHash(storageAddress, noteHash);
143
+ public writeNoteHash(contractAddress: Fr, noteHash: Fr) {
144
+ this.log.debug(`noteHashes(${contractAddress}) += @${noteHash}.`);
145
+ this.trace.traceNewNoteHash(contractAddress, noteHash);
140
146
  }
141
147
 
142
148
  /**
143
149
  * Check if a nullifier exists, trace the check.
144
- * @param storageAddress - address of the contract that the nullifier is associated with
150
+ * @param contractAddress - address of the contract that the nullifier is associated with
145
151
  * @param nullifier - the unsiloed nullifier to check
146
152
  * @returns exists - whether the nullifier exists in the nullifier set
147
153
  */
148
- public async checkNullifierExists(storageAddress: Fr, nullifier: Fr): Promise<boolean> {
149
- const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(storageAddress, nullifier);
154
+ public async checkNullifierExists(contractAddress: Fr, nullifier: Fr): Promise<boolean> {
155
+ const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(contractAddress, nullifier);
150
156
  this.log.debug(
151
- `nullifiers(${storageAddress})@${nullifier} ?? leafIndex: ${leafIndex}, exists: ${exists}, pending: ${isPending}.`,
157
+ `nullifiers(${contractAddress})@${nullifier} ?? leafIndex: ${leafIndex}, exists: ${exists}, pending: ${isPending}.`,
152
158
  );
153
- this.trace.traceNullifierCheck(storageAddress, nullifier, leafIndex, exists, isPending);
159
+ this.trace.traceNullifierCheck(contractAddress, nullifier, leafIndex, exists, isPending);
154
160
  return Promise.resolve(exists);
155
161
  }
156
162
 
157
163
  /**
158
164
  * Write a nullifier to the nullifier set, trace the write.
159
- * @param storageAddress - address of the contract that the nullifier is associated with
165
+ * @param contractAddress - address of the contract that the nullifier is associated with
160
166
  * @param nullifier - the unsiloed nullifier to write
161
167
  */
162
- public async writeNullifier(storageAddress: Fr, nullifier: Fr) {
163
- this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`);
168
+ public async writeNullifier(contractAddress: Fr, nullifier: Fr) {
169
+ this.log.debug(`nullifiers(${contractAddress}) += ${nullifier}.`);
164
170
  // Cache pending nullifiers for later access
165
- await this.nullifiers.append(storageAddress, nullifier);
171
+ await this.nullifiers.append(contractAddress, nullifier);
166
172
  // Trace all nullifier creations (even reverted ones)
167
- this.trace.traceNewNullifier(storageAddress, nullifier);
173
+ this.trace.traceNewNullifier(contractAddress, nullifier);
168
174
  }
169
175
 
170
176
  /**
@@ -210,22 +216,26 @@ export class AvmPersistableStateManager {
210
216
  /**
211
217
  * Get a contract instance.
212
218
  * @param contractAddress - address of the contract instance to retrieve.
213
- * @returns the contract instance with an "exists" flag
219
+ * @returns the contract instance or undefined if it does not exist.
214
220
  */
215
- public async getContractInstance(contractAddress: Fr): Promise<TracedContractInstance> {
216
- let exists = true;
217
- const aztecAddress = AztecAddress.fromField(contractAddress);
218
- let instance = await this.worldStateDB.getContractInstance(aztecAddress);
219
- if (instance === undefined) {
220
- instance = SerializableContractInstance.empty().withAddress(aztecAddress);
221
- exists = false;
221
+ public async getContractInstance(contractAddress: Fr): Promise<SerializableContractInstance | undefined> {
222
+ this.log.debug(`Getting contract instance for address ${contractAddress}`);
223
+ const instanceWithAddress = await this.worldStateDB.getContractInstance(AztecAddress.fromField(contractAddress));
224
+ const exists = instanceWithAddress !== undefined;
225
+
226
+ if (exists) {
227
+ const instance = new SerializableContractInstance(instanceWithAddress);
228
+ this.log.debug(
229
+ `Got contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`,
230
+ );
231
+ this.trace.traceGetContractInstance(contractAddress, exists, instance);
232
+
233
+ return Promise.resolve(instance);
234
+ } else {
235
+ this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
236
+ this.trace.traceGetContractInstance(contractAddress, exists);
237
+ return Promise.resolve(undefined);
222
238
  }
223
- this.log.debug(
224
- `Get Contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`,
225
- );
226
- const tracedInstance = { ...instance, exists };
227
- this.trace.traceGetContractInstance(tracedInstance);
228
- return Promise.resolve(tracedInstance);
229
239
  }
230
240
 
231
241
  /**
@@ -237,10 +247,43 @@ export class AvmPersistableStateManager {
237
247
  }
238
248
 
239
249
  /**
240
- * Get a contract's bytecode from the contracts DB
250
+ * Get a contract's bytecode from the contracts DB, also trace the contract class and instance
241
251
  */
242
- public async getBytecode(contractAddress: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
243
- return await this.worldStateDB.getBytecode(contractAddress, selector);
252
+ public async getBytecode(contractAddress: AztecAddress): Promise<Buffer | undefined> {
253
+ this.log.debug(`Getting bytecode for contract address ${contractAddress}`);
254
+ const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
255
+ const exists = instanceWithAddress !== undefined;
256
+
257
+ if (exists) {
258
+ const instance = new SerializableContractInstance(instanceWithAddress);
259
+
260
+ const contractClass = await this.worldStateDB.getContractClass(instance.contractClassId);
261
+ assert(
262
+ contractClass,
263
+ `Contract class not found in DB, but a contract instance was found with this class ID (${instance.contractClassId}). This should not happen!`,
264
+ );
265
+
266
+ const contractClassPreimage = {
267
+ artifactHash: contractClass.artifactHash,
268
+ privateFunctionsRoot: contractClass.privateFunctionsRoot,
269
+ publicBytecodeCommitment: computePublicBytecodeCommitment(contractClass.packedBytecode),
270
+ };
271
+
272
+ this.trace.traceGetBytecode(
273
+ contractAddress,
274
+ exists,
275
+ contractClass.packedBytecode,
276
+ instance,
277
+ contractClassPreimage,
278
+ );
279
+ return contractClass.packedBytecode;
280
+ } else {
281
+ // If the contract instance is not found, we assume it has not been deployed.
282
+ // It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
283
+ // This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
284
+ this.trace.traceGetBytecode(contractAddress, exists); // bytecode, instance, class undefined
285
+ return undefined;
286
+ }
244
287
  }
245
288
 
246
289
  /**
@@ -37,17 +37,17 @@ export class NullifierManager {
37
37
  /**
38
38
  * Get a nullifier's existence in this' cache or parent's (recursively).
39
39
  * DOES NOT CHECK HOST STORAGE!
40
- * @param storageAddress - the address of the contract whose storage is being read from
40
+ * @param contractAddress - the address of the contract whose storage is being read from
41
41
  * @param nullifier - the nullifier to check for
42
42
  * @returns exists: whether the nullifier exists in cache here or in parent's
43
43
  */
44
- private checkExistsHereOrParent(storageAddress: Fr, nullifier: Fr): boolean {
44
+ private checkExistsHereOrParent(contractAddress: Fr, nullifier: Fr): boolean {
45
45
  // First check this cache
46
- let existsAsPending = this.cache.exists(storageAddress, nullifier);
46
+ let existsAsPending = this.cache.exists(contractAddress, nullifier);
47
47
  // Then try parent's nullifier cache
48
48
  if (!existsAsPending && this.parent) {
49
49
  // Note: this will recurse to grandparent/etc until a cache-hit is encountered.
50
- existsAsPending = this.parent.checkExistsHereOrParent(storageAddress, nullifier);
50
+ existsAsPending = this.parent.checkExistsHereOrParent(contractAddress, nullifier);
51
51
  }
52
52
  return existsAsPending;
53
53
  }
@@ -59,24 +59,24 @@ export class NullifierManager {
59
59
  * 3. Fall back to the host state.
60
60
  * 4. Not found! Nullifier does not exist.
61
61
  *
62
- * @param storageAddress - the address of the contract whose storage is being read from
62
+ * @param contractAddress - the address of the contract whose storage is being read from
63
63
  * @param nullifier - the nullifier to check for
64
64
  * @returns exists: whether the nullifier exists at all,
65
65
  * isPending: whether the nullifier was found in a cache,
66
66
  * leafIndex: the nullifier's leaf index if it exists and is not pending (comes from host state).
67
67
  */
68
68
  public async checkExists(
69
- storageAddress: Fr,
69
+ contractAddress: Fr,
70
70
  nullifier: Fr,
71
71
  ): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
72
72
  // Check this cache and parent's (recursively)
73
- const existsAsPending = this.checkExistsHereOrParent(storageAddress, nullifier);
73
+ const existsAsPending = this.checkExistsHereOrParent(contractAddress, nullifier);
74
74
  // Finally try the host's Aztec state (a trip to the database)
75
75
  // If the value is found in the database, it will be associated with a leaf index!
76
76
  let leafIndex: bigint | undefined = undefined;
77
77
  if (!existsAsPending) {
78
78
  // silo the nullifier before checking for its existence in the host
79
- leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(storageAddress, nullifier));
79
+ leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(contractAddress, nullifier));
80
80
  }
81
81
  const exists = existsAsPending || leafIndex !== undefined;
82
82
  leafIndex = leafIndex === undefined ? BigInt(0) : leafIndex;
@@ -86,17 +86,17 @@ export class NullifierManager {
86
86
  /**
87
87
  * Stage a new nullifier (append it to the cache).
88
88
  *
89
- * @param storageAddress - the address of the contract that the nullifier is associated with
89
+ * @param contractAddress - the address of the contract that the nullifier is associated with
90
90
  * @param nullifier - the nullifier to stage
91
91
  */
92
- public async append(storageAddress: Fr, nullifier: Fr) {
93
- const [exists, ,] = await this.checkExists(storageAddress, nullifier);
92
+ public async append(contractAddress: Fr, nullifier: Fr) {
93
+ const [exists, ,] = await this.checkExists(contractAddress, nullifier);
94
94
  if (exists) {
95
95
  throw new NullifierCollisionError(
96
- `Nullifier ${nullifier} at contract ${storageAddress} already exists in parent cache or host.`,
96
+ `Nullifier ${nullifier} at contract ${contractAddress} already exists in parent cache or host.`,
97
97
  );
98
98
  }
99
- this.cache.append(storageAddress, nullifier);
99
+ this.cache.append(contractAddress, nullifier);
100
100
  }
101
101
 
102
102
  /**
@@ -135,35 +135,35 @@ export class NullifierCache {
135
135
  /**
136
136
  * Check whether a nullifier exists in the cache.
137
137
  *
138
- * @param storageAddress - the address of the contract that the nullifier is associated with
138
+ * @param contractAddress - the address of the contract that the nullifier is associated with
139
139
  * @param nullifier - the nullifier to check existence of
140
140
  * @returns whether the nullifier is found in the cache
141
141
  */
142
- public exists(storageAddress: Fr, nullifier: Fr): boolean {
142
+ public exists(contractAddress: Fr, nullifier: Fr): boolean {
143
143
  const exists =
144
- this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()) ||
145
- this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(storageAddress), nullifier).toBigInt());
144
+ this.cachePerContract.get(contractAddress.toBigInt())?.has(nullifier.toBigInt()) ||
145
+ this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(contractAddress), nullifier).toBigInt());
146
146
  return !!exists;
147
147
  }
148
148
 
149
149
  /**
150
150
  * Stage a new nullifier (append it to the cache).
151
151
  *
152
- * @param storageAddress - the address of the contract that the nullifier is associated with
152
+ * @param contractAddress - the address of the contract that the nullifier is associated with
153
153
  * @param nullifier - the nullifier to stage
154
154
  */
155
- public append(storageAddress: Fr, nullifier: Fr) {
156
- if (this.exists(storageAddress, nullifier)) {
155
+ public append(contractAddress: Fr, nullifier: Fr) {
156
+ if (this.exists(contractAddress, nullifier)) {
157
157
  throw new NullifierCollisionError(
158
- `Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
158
+ `Nullifier ${nullifier} at contract ${contractAddress} already exists in cache.`,
159
159
  );
160
160
  }
161
161
 
162
- let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt());
162
+ let nullifiersForContract = this.cachePerContract.get(contractAddress.toBigInt());
163
163
  // If this contract's nullifier set has no cached nullifiers, create a new Set to store them
164
164
  if (!nullifiersForContract) {
165
165
  nullifiersForContract = new Set();
166
- this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract);
166
+ this.cachePerContract.set(contractAddress.toBigInt(), nullifiersForContract);
167
167
  }
168
168
  nullifiersForContract.add(nullifier.toBigInt());
169
169
  }
@@ -45,17 +45,17 @@ export class PublicStorage {
45
45
  * Read a storage value from this' cache or parent's (recursively).
46
46
  * DOES NOT CHECK HOST STORAGE!
47
47
  *
48
- * @param storageAddress - the address of the contract whose storage is being read from
48
+ * @param contractAddress - the address of the contract whose storage is being read from
49
49
  * @param slot - the slot in the contract's storage being read from
50
50
  * @returns value: the latest value written according to this cache or the parent's. undefined on cache miss.
51
51
  */
52
- public readHereOrParent(storageAddress: Fr, slot: Fr): Fr | undefined {
52
+ public readHereOrParent(contractAddress: Fr, slot: Fr): Fr | undefined {
53
53
  // First try check this storage cache
54
- let value = this.cache.read(storageAddress, slot);
54
+ let value = this.cache.read(contractAddress, slot);
55
55
  // Then try parent's storage cache
56
56
  if (!value && this.parent) {
57
57
  // Note: this will recurse to grandparent/etc until a cache-hit is encountered.
58
- value = this.parent.readHereOrParent(storageAddress, slot);
58
+ value = this.parent.readHereOrParent(contractAddress, slot);
59
59
  }
60
60
  return value;
61
61
  }
@@ -67,17 +67,17 @@ export class PublicStorage {
67
67
  * 3. Fall back to the host state.
68
68
  * 4. Not found! Value has never been written to before. Flag it as non-existent and return value zero.
69
69
  *
70
- * @param storageAddress - the address of the contract whose storage is being read from
70
+ * @param contractAddress - the address of the contract whose storage is being read from
71
71
  * @param slot - the slot in the contract's storage being read from
72
72
  * @returns exists: whether the slot has EVER been written to before, value: the latest value written to slot, or 0 if never written to before
73
73
  */
74
- public async read(storageAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
74
+ public async read(contractAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
75
75
  let cached = false;
76
76
  // Check this cache and parent's (recursively)
77
- let value = this.readHereOrParent(storageAddress, slot);
77
+ let value = this.readHereOrParent(contractAddress, slot);
78
78
  // Finally try the host's Aztec state (a trip to the database)
79
79
  if (!value) {
80
- value = await this.hostPublicStorage.storageRead(storageAddress, slot);
80
+ value = await this.hostPublicStorage.storageRead(contractAddress, slot);
81
81
  // TODO(dbanks12): if value retrieved from host storage, we can cache it here
82
82
  // any future reads to the same slot can read from cache instead of more expensive
83
83
  // DB access
@@ -93,12 +93,12 @@ export class PublicStorage {
93
93
  /**
94
94
  * Stage a storage write.
95
95
  *
96
- * @param storageAddress - the address of the contract whose storage is being written to
96
+ * @param contractAddress - the address of the contract whose storage is being written to
97
97
  * @param slot - the slot in the contract's storage being written to
98
98
  * @param value - the value being written to the slot
99
99
  */
100
- public write(storageAddress: Fr, slot: Fr, value: Fr) {
101
- this.cache.write(storageAddress, slot, value);
100
+ public write(contractAddress: Fr, slot: Fr, value: Fr) {
101
+ this.cache.write(contractAddress, slot, value);
102
102
  }
103
103
 
104
104
  /**
@@ -114,9 +114,9 @@ export class PublicStorage {
114
114
  * Commits ALL staged writes to the host's state.
115
115
  */
116
116
  public async commitToDB() {
117
- for (const [storageAddress, cacheAtContract] of this.cache.cachePerContract) {
117
+ for (const [contractAddress, cacheAtContract] of this.cache.cachePerContract) {
118
118
  for (const [slot, value] of cacheAtContract) {
119
- await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(storageAddress), new Fr(slot), value);
119
+ await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(contractAddress), new Fr(slot), value);
120
120
  }
121
121
  }
122
122
  }
@@ -139,27 +139,27 @@ class PublicStorageCache {
139
139
  /**
140
140
  * Read a staged value from storage, if it has been previously written to.
141
141
  *
142
- * @param storageAddress - the address of the contract whose storage is being read from
142
+ * @param contractAddress - the address of the contract whose storage is being read from
143
143
  * @param slot - the slot in the contract's storage being read from
144
144
  * @returns the latest value written to slot, or undefined if no value has been written
145
145
  */
146
- public read(storageAddress: Fr, slot: Fr): Fr | undefined {
147
- return this.cachePerContract.get(storageAddress.toBigInt())?.get(slot.toBigInt());
146
+ public read(contractAddress: Fr, slot: Fr): Fr | undefined {
147
+ return this.cachePerContract.get(contractAddress.toBigInt())?.get(slot.toBigInt());
148
148
  }
149
149
 
150
150
  /**
151
151
  * Stage a storage write.
152
152
  *
153
- * @param storageAddress - the address of the contract whose storage is being written to
153
+ * @param contractAddress - the address of the contract whose storage is being written to
154
154
  * @param slot - the slot in the contract's storage being written to
155
155
  * @param value - the value being written to the slot
156
156
  */
157
- public write(storageAddress: Fr, slot: Fr, value: Fr) {
158
- let cacheAtContract = this.cachePerContract.get(storageAddress.toBigInt());
157
+ public write(contractAddress: Fr, slot: Fr, value: Fr) {
158
+ let cacheAtContract = this.cachePerContract.get(contractAddress.toBigInt());
159
159
  if (!cacheAtContract) {
160
160
  // If this contract's storage has no staged modifications, create a new inner map to store them
161
161
  cacheAtContract = new Map();
162
- this.cachePerContract.set(storageAddress.toBigInt(), cacheAtContract);
162
+ this.cachePerContract.set(contractAddress.toBigInt(), cacheAtContract);
163
163
  }
164
164
  cacheAtContract.set(slot.toBigInt(), value);
165
165
  }