@aztec/simulator 0.0.1-commit.1bea0213 → 0.0.1-commit.1dcfe2301

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 (145) hide show
  1. package/README.md +4 -4
  2. package/dest/private/acvm/acvm.d.ts +4 -2
  3. package/dest/private/acvm/acvm.d.ts.map +1 -1
  4. package/dest/private/acvm/acvm.js +4 -3
  5. package/dest/private/acvm_native.d.ts +5 -3
  6. package/dest/private/acvm_native.d.ts.map +1 -1
  7. package/dest/private/acvm_native.js +8 -6
  8. package/dest/private/acvm_wasm.d.ts +4 -3
  9. package/dest/private/acvm_wasm.d.ts.map +1 -1
  10. package/dest/private/acvm_wasm.js +4 -4
  11. package/dest/private/circuit_recording/circuit_recorder.d.ts +4 -3
  12. package/dest/private/circuit_recording/circuit_recorder.d.ts.map +1 -1
  13. package/dest/private/circuit_recording/circuit_recorder.js +7 -5
  14. package/dest/private/circuit_recording/file_circuit_recorder.d.ts +3 -2
  15. package/dest/private/circuit_recording/file_circuit_recorder.d.ts.map +1 -1
  16. package/dest/private/circuit_recording/file_circuit_recorder.js +2 -2
  17. package/dest/private/circuit_recording/memory_circuit_recorder.d.ts +7 -2
  18. package/dest/private/circuit_recording/memory_circuit_recorder.d.ts.map +1 -1
  19. package/dest/private/circuit_recording/memory_circuit_recorder.js +4 -4
  20. package/dest/private/factory.d.ts +3 -3
  21. package/dest/private/factory.d.ts.map +1 -1
  22. package/dest/private/factory.js +7 -4
  23. package/dest/public/avm/avm_gas.js +3 -3
  24. package/dest/public/avm/avm_simulator.js +1 -1
  25. package/dest/public/avm/calldata.d.ts +1 -1
  26. package/dest/public/avm/calldata.d.ts.map +1 -1
  27. package/dest/public/avm/calldata.js +3 -2
  28. package/dest/public/avm/fixtures/account_proof_fetcher.d.ts +2 -0
  29. package/dest/public/avm/fixtures/account_proof_fetcher.d.ts.map +1 -0
  30. package/dest/public/avm/fixtures/account_proof_fetcher.js +152 -0
  31. package/dest/public/avm/opcodes/accrued_substate.d.ts +4 -5
  32. package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
  33. package/dest/public/avm/opcodes/accrued_substate.js +11 -16
  34. package/dest/public/avm/serialization/bytecode_serialization.js +3 -3
  35. package/dest/public/avm/serialization/instruction_serialization.d.ts +2 -2
  36. package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
  37. package/dest/public/avm/serialization/instruction_serialization.js +1 -1
  38. package/dest/public/contracts_db_checkpoint.d.ts +2 -2
  39. package/dest/public/contracts_db_checkpoint.d.ts.map +1 -1
  40. package/dest/public/contracts_db_checkpoint.js +1 -1
  41. package/dest/public/executor_metrics.d.ts +1 -1
  42. package/dest/public/executor_metrics.d.ts.map +1 -1
  43. package/dest/public/executor_metrics.js +7 -2
  44. package/dest/public/fixtures/amm_test.js +2 -2
  45. package/dest/public/fixtures/bulk_test.d.ts +1 -1
  46. package/dest/public/fixtures/bulk_test.d.ts.map +1 -1
  47. package/dest/public/fixtures/bulk_test.js +4 -4
  48. package/dest/public/fixtures/opcode_spammer.d.ts +3 -4
  49. package/dest/public/fixtures/opcode_spammer.d.ts.map +1 -1
  50. package/dest/public/fixtures/opcode_spammer.js +16 -56
  51. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +6 -5
  52. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  53. package/dest/public/fixtures/public_tx_simulation_tester.js +37 -10
  54. package/dest/public/fixtures/utils.d.ts +2 -2
  55. package/dest/public/fixtures/utils.d.ts.map +1 -1
  56. package/dest/public/fixtures/utils.js +10 -10
  57. package/dest/public/hinting_db_sources.d.ts +5 -5
  58. package/dest/public/hinting_db_sources.d.ts.map +1 -1
  59. package/dest/public/hinting_db_sources.js +7 -6
  60. package/dest/public/public_db_sources.d.ts +6 -5
  61. package/dest/public/public_db_sources.d.ts.map +1 -1
  62. package/dest/public/public_db_sources.js +14 -14
  63. package/dest/public/public_processor/guarded_merkle_tree.d.ts +5 -5
  64. package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
  65. package/dest/public/public_processor/guarded_merkle_tree.js +5 -5
  66. package/dest/public/public_processor/public_processor.d.ts +8 -4
  67. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  68. package/dest/public/public_processor/public_processor.js +60 -47
  69. package/dest/public/public_processor/public_processor_metrics.d.ts +2 -2
  70. package/dest/public/public_processor/public_processor_metrics.d.ts.map +1 -1
  71. package/dest/public/public_processor/public_processor_metrics.js +20 -4
  72. package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts +3 -2
  73. package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts.map +1 -1
  74. package/dest/public/public_tx_simulator/contract_provider_for_cpp.js +4 -3
  75. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts +5 -5
  76. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts.map +1 -1
  77. package/dest/public/public_tx_simulator/cpp_public_tx_simulator.js +10 -11
  78. package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.d.ts +4 -4
  79. package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.d.ts.map +1 -1
  80. package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.js +7 -7
  81. package/dest/public/public_tx_simulator/cpp_vs_ts_public_tx_simulator.d.ts +4 -4
  82. package/dest/public/public_tx_simulator/cpp_vs_ts_public_tx_simulator.d.ts.map +1 -1
  83. package/dest/public/public_tx_simulator/cpp_vs_ts_public_tx_simulator.js +6 -6
  84. package/dest/public/public_tx_simulator/dumping_cpp_public_tx_simulator.d.ts +3 -2
  85. package/dest/public/public_tx_simulator/dumping_cpp_public_tx_simulator.d.ts.map +1 -1
  86. package/dest/public/public_tx_simulator/dumping_cpp_public_tx_simulator.js +2 -2
  87. package/dest/public/public_tx_simulator/factories.d.ts +3 -2
  88. package/dest/public/public_tx_simulator/factories.d.ts.map +1 -1
  89. package/dest/public/public_tx_simulator/factories.js +4 -4
  90. package/dest/public/public_tx_simulator/public_tx_context.d.ts +10 -5
  91. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  92. package/dest/public/public_tx_simulator/public_tx_context.js +16 -18
  93. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +9 -4
  94. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  95. package/dest/public/public_tx_simulator/public_tx_simulator.js +19 -12
  96. package/dest/public/side_effect_trace.d.ts +4 -4
  97. package/dest/public/side_effect_trace.d.ts.map +1 -1
  98. package/dest/public/side_effect_trace.js +3 -3
  99. package/dest/public/state_manager/state_manager.d.ts +10 -4
  100. package/dest/public/state_manager/state_manager.d.ts.map +1 -1
  101. package/dest/public/state_manager/state_manager.js +12 -5
  102. package/dest/public/test_executor_metrics.d.ts +8 -2
  103. package/dest/public/test_executor_metrics.d.ts.map +1 -1
  104. package/dest/public/test_executor_metrics.js +24 -2
  105. package/package.json +15 -16
  106. package/src/private/acvm/acvm.ts +4 -3
  107. package/src/private/acvm_native.ts +11 -5
  108. package/src/private/acvm_wasm.ts +7 -3
  109. package/src/private/circuit_recording/circuit_recorder.ts +7 -5
  110. package/src/private/circuit_recording/file_circuit_recorder.ts +7 -2
  111. package/src/private/circuit_recording/memory_circuit_recorder.ts +6 -4
  112. package/src/private/factory.ts +7 -4
  113. package/src/public/avm/avm_gas.ts +2 -2
  114. package/src/public/avm/avm_simulator.ts +1 -1
  115. package/src/public/avm/calldata.ts +3 -2
  116. package/src/public/avm/fixtures/account_proof.json +553 -0
  117. package/src/public/avm/fixtures/account_proof_fetcher.ts +166 -0
  118. package/src/public/avm/opcodes/accrued_substate.ts +10 -19
  119. package/src/public/avm/opcodes/external_calls.ts +1 -1
  120. package/src/public/avm/serialization/bytecode_serialization.ts +2 -2
  121. package/src/public/avm/serialization/instruction_serialization.ts +1 -1
  122. package/src/public/contracts_db_checkpoint.ts +1 -1
  123. package/src/public/executor_metrics.ts +4 -1
  124. package/src/public/fixtures/amm_test.ts +2 -2
  125. package/src/public/fixtures/bulk_test.ts +2 -4
  126. package/src/public/fixtures/opcode_spammer.ts +18 -55
  127. package/src/public/fixtures/public_tx_simulation_tester.ts +47 -6
  128. package/src/public/fixtures/utils.ts +17 -12
  129. package/src/public/fuzzing/avm_fuzzer_simulator.ts +1 -1
  130. package/src/public/hinting_db_sources.ts +9 -7
  131. package/src/public/public_db_sources.ts +27 -19
  132. package/src/public/public_processor/guarded_merkle_tree.ts +6 -6
  133. package/src/public/public_processor/public_processor.ts +86 -60
  134. package/src/public/public_processor/public_processor_metrics.ts +10 -4
  135. package/src/public/public_tx_simulator/contract_provider_for_cpp.ts +8 -4
  136. package/src/public/public_tx_simulator/cpp_public_tx_simulator.ts +10 -8
  137. package/src/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.ts +7 -5
  138. package/src/public/public_tx_simulator/cpp_vs_ts_public_tx_simulator.ts +7 -5
  139. package/src/public/public_tx_simulator/dumping_cpp_public_tx_simulator.ts +3 -1
  140. package/src/public/public_tx_simulator/factories.ts +6 -3
  141. package/src/public/public_tx_simulator/public_tx_context.ts +21 -16
  142. package/src/public/public_tx_simulator/public_tx_simulator.ts +20 -12
  143. package/src/public/side_effect_trace.ts +5 -2
  144. package/src/public/state_manager/state_manager.ts +27 -4
  145. package/src/public/test_executor_metrics.ts +27 -3
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Fetches an account proof from the Ethereum mainnet and saves it as account_proof.json.
3
+ * This script is not using any Aztec library code, so it's easily portable.
4
+ */
5
+ import fs from 'fs';
6
+ import { dirname, join } from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import { createPublicClient, fromRlp, hexToBytes, http } from 'viem';
9
+ import { mainnet } from 'viem/chains';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+
13
+ const RPC_URL = process.env.RPC_URL;
14
+ const ADDRESS = (process.env.ADDRESS || '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045') as `0x${string}`;
15
+ const BLOCK_TAG = process.env.BLOCK_NUMBER ? BigInt(process.env.BLOCK_NUMBER) : 'latest';
16
+ const MAX_ACCOUNT_PATH = 15;
17
+
18
+ function padTo(arr: number[], len: number) {
19
+ return [...arr, ...Array(len - arr.length).fill(0)].slice(0, len);
20
+ }
21
+
22
+ function toBytes(hex: `0x${string}`) {
23
+ return Array.from(hexToBytes(hex));
24
+ }
25
+
26
+ function bytesToU64s(bytes: number[]) {
27
+ const paddedBytes = padTo(bytes, 32);
28
+ return Array.from({ length: 4 }, (_, i) => {
29
+ let val = 0n;
30
+ for (let j = 0; j < 8; j++) {
31
+ val += BigInt(paddedBytes[i * 8 + j]) << BigInt(j * 8);
32
+ }
33
+ return val.toString();
34
+ });
35
+ }
36
+
37
+ function toBytesAndLen(val: bigint | number) {
38
+ if (val === 0n || val === 0) {
39
+ return { bytes: [0], length: 0 };
40
+ }
41
+ let hex = val.toString(16);
42
+ if (hex.length % 2) {
43
+ hex = '0' + hex;
44
+ }
45
+ const bytes = toBytes(`0x${hex}`);
46
+ return { bytes, length: bytes.length };
47
+ }
48
+
49
+ function parseNode(rlp: `0x${string}`) {
50
+ // Should be safe when working with branches and extensions without embedded children.
51
+ const decoded = fromRlp(rlp) as `0x${string}`[];
52
+ const node = {
53
+ rows: Array(16)
54
+ .fill(0)
55
+ .map(() => Array(32).fill(0)),
56
+ row_exist: Array(16).fill(false),
57
+ node_type: 0,
58
+ };
59
+
60
+ if (decoded.length === 17) {
61
+ for (let i = 0; i < 16; i++) {
62
+ if (decoded[i] !== '0x') {
63
+ node.row_exist[i] = true;
64
+ node.rows[i] = padTo(toBytes(decoded[i]), 32);
65
+ }
66
+ }
67
+ } else if (decoded.length === 2) {
68
+ const keyBytes = toBytes(decoded[0]);
69
+ const prefix = keyBytes[0];
70
+ if (prefix >> 4 >= 2) {
71
+ throw new Error('Unsupported: leaf node in proof path');
72
+ }
73
+ node.node_type = 1;
74
+ // Extension header format expected by the noir code: check out storage_proof types.nr.
75
+ node.rows[0][0] = prefix >> 4;
76
+ node.rows[0][8] = prefix & 0x0f;
77
+ node.rows[0][16] = keyBytes.length - 1;
78
+
79
+ for (let i = 1; i < keyBytes.length && i < 32; i++) {
80
+ node.rows[1][i - 1] = keyBytes[i];
81
+ }
82
+ node.rows[2] = padTo(toBytes(decoded[1]), 32);
83
+ node.row_exist[0] = node.row_exist[1] = node.row_exist[2] = true;
84
+ }
85
+ return node;
86
+ }
87
+
88
+ function parseProof(proof: `0x${string}`[], maxLen: number) {
89
+ const nodes = proof.slice(0, -1).slice(0, maxLen).map(parseNode);
90
+ while (nodes.length < maxLen) {
91
+ nodes.push({
92
+ rows: Array(16)
93
+ .fill(0)
94
+ .map(() => Array(32).fill(0)),
95
+ row_exist: Array(16).fill(false),
96
+ node_type: 0,
97
+ });
98
+ }
99
+ return nodes;
100
+ }
101
+
102
+ function nodeToLibFormat(node: { rows: number[][]; row_exist: boolean[]; node_type: number }) {
103
+ return {
104
+ rows: node.rows.map(bytesToU64s),
105
+ row_exist: node.row_exist,
106
+ node_type: String(node.node_type),
107
+ };
108
+ }
109
+
110
+ async function main() {
111
+ if (!RPC_URL) {
112
+ throw new Error('RPC_URL is not set');
113
+ }
114
+ console.log(`Fetching account proof for ${ADDRESS}`);
115
+
116
+ const client = createPublicClient({
117
+ chain: mainnet,
118
+ transport: http(RPC_URL),
119
+ });
120
+
121
+ const [blockNumber, proof, block] = await Promise.all([
122
+ client.getBlockNumber(),
123
+ client.getProof({
124
+ address: ADDRESS,
125
+ storageKeys: [],
126
+ blockNumber: BLOCK_TAG === 'latest' ? undefined : BLOCK_TAG,
127
+ }),
128
+ client.getBlock({
129
+ blockNumber: BLOCK_TAG === 'latest' ? undefined : BLOCK_TAG,
130
+ }),
131
+ ]);
132
+
133
+ console.log(`Block: ${blockNumber}, Account nodes: ${proof.accountProof.length}`);
134
+
135
+ // The -1 is because the last node in the proof is the leaf, which is excluded from path verification.
136
+ const accountPathLen = proof.accountProof.length - 1;
137
+ if (accountPathLen > MAX_ACCOUNT_PATH) {
138
+ throw new Error(
139
+ `Account proof path length ${accountPathLen} exceeds MAX_ACCOUNT_PATH ${MAX_ACCOUNT_PATH}. Increase the limit.`,
140
+ );
141
+ }
142
+
143
+ const nonce = toBytesAndLen(proof.nonce);
144
+ const balance = toBytesAndLen(proof.balance);
145
+
146
+ const data = {
147
+ block_number: String(blockNumber),
148
+ node_length: String(accountPathLen),
149
+ root: bytesToU64s(toBytes(block.stateRoot)),
150
+ nodes: parseProof(proof.accountProof, MAX_ACCOUNT_PATH).map(nodeToLibFormat),
151
+ account: {
152
+ address: toBytes(ADDRESS).map(String),
153
+ balance: padTo(balance.bytes, 32).map(String),
154
+ balance_length: String(balance.length),
155
+ code_hash: bytesToU64s(toBytes(proof.codeHash)),
156
+ nonce: padTo(nonce.bytes, 8).map(String),
157
+ nonce_length: String(nonce.length),
158
+ storage_hash: bytesToU64s(toBytes(proof.storageHash)),
159
+ },
160
+ };
161
+
162
+ fs.writeFileSync(join(__dirname, 'account_proof.json'), JSON.stringify(data, null, 2));
163
+ console.log('account_proof.json generated');
164
+ }
165
+
166
+ main().catch(console.error);
@@ -88,18 +88,11 @@ export class NullifierExists extends Instruction {
88
88
  static type: string = 'NULLIFIEREXISTS';
89
89
  static readonly opcode: Opcode = Opcode.NULLIFIEREXISTS;
90
90
  // Informs (de)serialization. See Instruction.deserialize.
91
- static readonly wireFormat = [
92
- OperandType.UINT8,
93
- OperandType.UINT8,
94
- OperandType.UINT16,
95
- OperandType.UINT16,
96
- OperandType.UINT16,
97
- ];
91
+ static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT16, OperandType.UINT16];
98
92
 
99
93
  constructor(
100
94
  private addressingMode: number,
101
- private nullifierOffset: number,
102
- private addressOffset: number,
95
+ private siloedNullifierOffset: number,
103
96
  private existsOffset: number,
104
97
  ) {
105
98
  super();
@@ -113,13 +106,12 @@ export class NullifierExists extends Instruction {
113
106
  this.baseGasCost(addressing.indirectOperandsCount(), addressing.relativeOperandsCount()),
114
107
  );
115
108
 
116
- const operands = [this.nullifierOffset, this.addressOffset, this.existsOffset];
117
- const [nullifierOffset, addressOffset, existsOffset] = addressing.resolve(operands, memory);
118
- memory.checkTags(TypeTag.FIELD, nullifierOffset, addressOffset);
109
+ const operands = [this.siloedNullifierOffset, this.existsOffset];
110
+ const [siloedNullifierOffset, existsOffset] = addressing.resolve(operands, memory);
111
+ memory.checkTag(TypeTag.FIELD, siloedNullifierOffset);
119
112
 
120
- const nullifier = memory.get(nullifierOffset).toFr();
121
- const address = memory.get(addressOffset).toAztecAddress();
122
- const exists = await context.persistableState.checkNullifierExists(address, nullifier);
113
+ const siloedNullifier = memory.get(siloedNullifierOffset).toFr();
114
+ const exists = await context.persistableState.checkSiloedNullifierExists(siloedNullifier);
123
115
 
124
116
  memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
125
117
  }
@@ -212,10 +204,9 @@ export class L1ToL2MessageExists extends Instruction {
212
204
  }
213
205
  }
214
206
 
215
- export class EmitUnencryptedLog extends Instruction {
216
- // TODO(#11124): rename unencrypted -> public
217
- static type: string = 'EMITUNENCRYPTEDLOG';
218
- static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG;
207
+ export class EmitPublicLog extends Instruction {
208
+ static type: string = 'EMITPUBLICLOG';
209
+ static readonly opcode: Opcode = Opcode.EMITPUBLICLOG;
219
210
  // Informs (de)serialization. See Instruction.deserialize.
220
211
  static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT16, OperandType.UINT16];
221
212
 
@@ -14,8 +14,8 @@ abstract class ExternalCall extends Instruction {
14
14
  OperandType.UINT16, // L2 gas offset
15
15
  OperandType.UINT16, // DA gas offset
16
16
  OperandType.UINT16, // Address offset
17
- OperandType.UINT16, // Args offset
18
17
  OperandType.UINT16, // Args size offset
18
+ OperandType.UINT16, // Args offset
19
19
  ];
20
20
 
21
21
  constructor(
@@ -19,7 +19,7 @@ import {
19
19
  EcAdd,
20
20
  EmitNoteHash,
21
21
  EmitNullifier,
22
- EmitUnencryptedLog,
22
+ EmitPublicLog,
23
23
  Eq,
24
24
  FieldDiv,
25
25
  GetContractInstance,
@@ -129,7 +129,7 @@ export const INSTRUCTION_SET = new Map<Opcode, InstructionDeserializer>([
129
129
  [L1ToL2MessageExists.opcode, Instruction.fromBuffer.bind(L1ToL2MessageExists)], // Messages
130
130
 
131
131
  // Accrued Substate
132
- [EmitUnencryptedLog.opcode, Instruction.fromBuffer.bind(EmitUnencryptedLog)],
132
+ [EmitPublicLog.opcode, Instruction.fromBuffer.bind(EmitPublicLog)],
133
133
  [SendL2ToL1Message.opcode, Instruction.fromBuffer.bind(SendL2ToL1Message)],
134
134
  [GetContractInstance.opcode, Instruction.fromBuffer.bind(GetContractInstance)],
135
135
 
@@ -70,7 +70,7 @@ export enum Opcode {
70
70
  EMITNULLIFIER,
71
71
  L1TOL2MSGEXISTS,
72
72
  GETCONTRACTINSTANCE,
73
- EMITUNENCRYPTEDLOG,
73
+ EMITPUBLICLOG,
74
74
  SENDL2TOL1MSG,
75
75
  // External calls
76
76
  CALL,
@@ -31,7 +31,7 @@ export class ContractsDbCheckpoint {
31
31
  return this.bytecodeCommitments.get(classId.toString());
32
32
  }
33
33
 
34
- public deepCopy(): ContractsDbCheckpoint {
34
+ public fork(): ContractsDbCheckpoint {
35
35
  const copy = new ContractsDbCheckpoint();
36
36
  this.instances.forEach((value, key) => copy.instances.set(key, value));
37
37
  this.classes.forEach((value, key) => copy.classes.set(key, value));
@@ -7,6 +7,7 @@ import {
7
7
  type TelemetryClient,
8
8
  type Tracer,
9
9
  type UpDownCounter,
10
+ createUpDownCounterWithDefault,
10
11
  } from '@aztec/telemetry-client';
11
12
 
12
13
  import type { ExecutorMetricsInterface } from './executor_metrics_interface.js';
@@ -25,7 +26,9 @@ export class ExecutorMetrics implements ExecutorMetricsInterface {
25
26
  this.tracer = client.getTracer(name);
26
27
  const meter = client.getMeter(name);
27
28
 
28
- this.fnCount = meter.createUpDownCounter(Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT);
29
+ this.fnCount = createUpDownCounterWithDefault(meter, Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT, {
30
+ [Attributes.OK]: [true, false],
31
+ });
29
32
 
30
33
  this.fnDuration = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_DURATION);
31
34
 
@@ -1,4 +1,4 @@
1
- import { GeneratorIndex } from '@aztec/constants';
1
+ import { DomainSeparator } from '@aztec/constants';
2
2
  import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import type { Logger } from '@aztec/foundation/log';
@@ -326,6 +326,6 @@ async function removeLiquidity(
326
326
  async function computePartialNoteValidityCommitment(partialNote: { commitment: Fr }, completer: AztecAddress) {
327
327
  return await poseidon2HashWithSeparator(
328
328
  [partialNote.commitment, completer],
329
- GeneratorIndex.PARTIAL_NOTE_VALIDITY_COMMITMENT,
329
+ DomainSeparator.PARTIAL_NOTE_VALIDITY_COMMITMENT,
330
330
  );
331
331
  }
@@ -30,9 +30,7 @@ export async function bulkTest(
30
30
  // for it to use as "expected" values when testing contract instance retrieval.
31
31
  const expectContractInstance = avmTestContract;
32
32
  const argsField = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(x => new Fr(x));
33
- const argsU8 = [1, 2, 3, 4, 5, 6, 7, 8].map(x => new Fr(x));
34
- argsU8.push(new Fr(2n ** 128n + 9n)); // Trigger truncation from large (> 128 bits) value (canonical decomposition event)
35
- argsU8.push(new Fr(2n ** 125n + 10n)); // Trigger truncation from small (< 128 bits) value (no canonical decomposition event)
33
+ const argsU8 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(x => new Fr(x));
36
34
  const args = [
37
35
  argsField,
38
36
  argsU8,
@@ -62,7 +60,7 @@ export async function bulkTest(
62
60
  {
63
61
  address: avmTestContract.address,
64
62
  fnName: 'assert_calldata_copy',
65
- args: [argsField.slice(3), /* with_selector: */ true],
63
+ args: [argsField.slice(0, 3), /* with_selector: */ true],
66
64
  },
67
65
  {
68
66
  address: avmTestContract.address,
@@ -143,7 +143,7 @@
143
143
  * - `EMITNOTEHASH`: max 64 per TX
144
144
  * - `EMITNULLIFIER`: max 63 per TX (one reserved for TX nullifier)
145
145
  * - `SENDL2TOL1MSG`: max 8 per TX
146
- * - `EMITUNENCRYPTEDLOG`: limited by total log payload size
146
+ * - `EMITPUBLICLOG`: limited by total log payload size
147
147
  *
148
148
  * By having the inner contract REVERT after emitting side effects, those effects are discarded, allowing the outer contract to call it again. This enables thousands of opcode executions per TX instead of just the limit.
149
149
  *
@@ -164,7 +164,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
164
164
  import type { Bufferable } from '@aztec/foundation/serialize';
165
165
  import { type CallStackMetadata, PublicDataWrite, type PublicTxResult } from '@aztec/stdlib/avm';
166
166
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
167
- import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/stdlib/hash';
167
+ import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
168
168
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
169
169
  import { MerkleTreeId } from '@aztec/stdlib/trees';
170
170
 
@@ -182,7 +182,7 @@ import {
182
182
  EcAdd,
183
183
  EmitNoteHash,
184
184
  EmitNullifier,
185
- EmitUnencryptedLog,
185
+ EmitPublicLog,
186
186
  Eq,
187
187
  FieldDiv,
188
188
  GetContractInstance,
@@ -295,9 +295,8 @@ export interface SpamConfigsForOpcode {
295
295
  export const WARM_NOTE_HASH = new Fr(0xdeadbeefn);
296
296
  export const WARM_L1_TO_L2_MSG = new Fr(0xcafebabedeadbeefn);
297
297
 
298
- /** Warm nullifier constants - uses a fixed address since NULLIFIEREXISTS takes address as parameter */
299
- export const WARM_NULLIFIER = new Fr(0xdeadbeef0001n);
300
- export const WARM_NULLIFIER_ADDRESS = AztecAddress.fromNumber(0xbeef);
298
+ /** Warm nullifier constant - a pre-siloed nullifier value inserted directly into the tree */
299
+ export const WARM_SILOED_NULLIFIER = new Fr(0xdeadbeef0001n);
301
300
 
302
301
  /** Warm storage constants - storage is inserted for the deployed contract's address */
303
302
  export const WARM_STORAGE_SLOT = new Fr(0xdeadbeef0002n);
@@ -331,9 +330,8 @@ export async function insertWarmTreeEntries(
331
330
  // Insert into L1 to L2 message tree
332
331
  await merkleTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [WARM_L1_TO_L2_MSG]);
333
332
 
334
- // Insert siloed nullifier into nullifier tree
335
- const siloedNullifier = await siloNullifier(WARM_NULLIFIER_ADDRESS, WARM_NULLIFIER);
336
- await merkleTrees.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()]);
333
+ // Insert siloed nullifier into nullifier tree (already siloed - used directly by NULLIFIEREXISTS)
334
+ await merkleTrees.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [WARM_SILOED_NULLIFIER.toBuffer()]);
337
335
 
338
336
  // Insert storage value into public data tree
339
337
  const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, WARM_STORAGE_SLOT);
@@ -1060,56 +1058,25 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
1060
1058
  [Opcode.NULLIFIEREXISTS]: [
1061
1059
  {
1062
1060
  label: 'Non-existent nullifier',
1061
+ // NULLIFIEREXISTS now takes a siloed nullifier directly (no address parameter)
1063
1062
  setup: [
1064
- { offset: 0, value: new Field(Fr.random()) }, // random nullifier
1065
- { offset: 1, value: new Field(Fr.random()) }, // random address
1063
+ { offset: 0, value: new Field(Fr.random()) }, // random siloed nullifier (won't exist)
1066
1064
  ],
1067
1065
  targetInstructions: () => [
1068
- new NullifierExists(/*addressing_mode=*/ 0, /*nullifierOffset=*/ 0, /*addressOffset=*/ 1, /*existsOffset=*/ 2),
1066
+ new NullifierExists(/*addressing_mode=*/ 0, /*siloedNullifierOffset=*/ 0, /*existsOffset=*/ 1),
1069
1067
  ],
1070
1068
  },
1071
1069
  {
1072
1070
  label: 'Existing nullifier (warm - from tree)',
1073
- // Uses pre-inserted nullifier from insertWarmTreeEntries()
1071
+ // Uses pre-inserted siloed nullifier from insertWarmTreeEntries()
1072
+ // NULLIFIEREXISTS now takes a siloed nullifier directly
1074
1073
  setup: [
1075
- { offset: 0, value: new Field(WARM_NULLIFIER) }, // pre-inserted nullifier
1076
- { offset: 1, value: new Field(WARM_NULLIFIER_ADDRESS.toField()) }, // address it was siloed with
1074
+ { offset: 0, value: new Field(WARM_SILOED_NULLIFIER) }, // pre-inserted siloed nullifier
1077
1075
  ],
1078
1076
  targetInstructions: () => [
1079
- new NullifierExists(/*addressing_mode=*/ 0, /*nullifierOffset=*/ 0, /*addressOffset=*/ 1, /*existsOffset=*/ 2),
1077
+ new NullifierExists(/*addressing_mode=*/ 0, /*siloedNullifierOffset=*/ 0, /*existsOffset=*/ 1),
1080
1078
  ],
1081
1079
  },
1082
- {
1083
- label: 'Existing nullifier (warm - EMITNULLIFIER first)',
1084
- // Memory layout: nullifier (incremented), constant 1, current address (from GETENVVAR), revertSize, exists result
1085
- setup: [
1086
- { offset: 0, value: new Field(Fr.random()) }, // nullifier (will be incremented)
1087
- { offset: 1, value: new Field(1n) }, // constant 1 for ADD
1088
- () => [
1089
- // Get current contract address into offset 2
1090
- new GetEnvVar(/*addressing_mode=*/ 0, /*dstOffset=*/ 2, /*varEnum=*/ 0).as(
1091
- Opcode.GETENVVAR_16,
1092
- GetEnvVar.wireFormat16,
1093
- ),
1094
- ],
1095
- { offset: 3, value: new Uint32(0n) }, // revertSize
1096
- ],
1097
- targetInstructions: () => [
1098
- new EmitNullifier(/*addressing_mode=*/ 0, /*nullifierOffset=*/ 0),
1099
- new NullifierExists(/*addressing_mode=*/ 0, /*nullifierOffset=*/ 0, /*addressOffset=*/ 2, /*existsOffset=*/ 4),
1100
- new Add(/*addressing_mode=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 0).as(
1101
- Opcode.ADD_8,
1102
- Add.wireFormat8,
1103
- ), // nullifier++
1104
- ],
1105
- cleanupInstructions: () => [
1106
- new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 3, /*returnOffset=*/ 0).as(
1107
- Opcode.REVERT_8,
1108
- Revert.wireFormat8,
1109
- ),
1110
- ],
1111
- limit: MAX_NULLIFIERS_PER_TX - 1,
1112
- },
1113
1080
  ],
1114
1081
 
1115
1082
  [Opcode.L1TOL2MSGEXISTS]: [
@@ -1275,17 +1242,15 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
1275
1242
  },
1276
1243
  ],
1277
1244
 
1278
- // EMITUNENCRYPTEDLOG - two configs: minimal (many small logs) and max-size (one large log)
1279
- [Opcode.EMITUNENCRYPTEDLOG]: [
1245
+ // EMITPUBLICLOG - two configs: minimal (many small logs) and max-size (one large log)
1246
+ [Opcode.EMITPUBLICLOG]: [
1280
1247
  {
1281
1248
  label: 'Many empty logs, revert, repeat',
1282
1249
  setup: [
1283
1250
  { offset: 0, value: new Uint32(0n) }, // logSize = 0 fields (minimal)
1284
1251
  { offset: 1, value: new Uint32(0n) }, // revertSize
1285
1252
  ],
1286
- targetInstructions: () => [
1287
- new EmitUnencryptedLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 1),
1288
- ], // logOffset doesn't matter when size is 0
1253
+ targetInstructions: () => [new EmitPublicLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 1)], // logOffset doesn't matter when size is 0
1289
1254
  cleanupInstructions: () => [
1290
1255
  new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 1, /*returnOffset=*/ 0).as(
1291
1256
  Opcode.REVERT_8,
@@ -1309,9 +1274,7 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
1309
1274
  // value: new Field(0n),
1310
1275
  //})),
1311
1276
  ],
1312
- targetInstructions: () => [
1313
- new EmitUnencryptedLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 2),
1314
- ], // uses logOffset 2 (uninitialized Field(0))
1277
+ targetInstructions: () => [new EmitPublicLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 2)], // uses logOffset 2 (uninitialized Field(0))
1315
1278
  cleanupInstructions: () => [
1316
1279
  new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 1, /*returnOffset=*/ 0).as(
1317
1280
  Opcode.REVERT_8,
@@ -1,11 +1,11 @@
1
- import { DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT } from '@aztec/constants';
1
+ import { PUBLIC_TX_L2_GAS_OVERHEAD, TX_DA_GAS_OVERHEAD } from '@aztec/constants';
2
2
  import { asyncMap } from '@aztec/foundation/async-map';
3
3
  import { BlockNumber } from '@aztec/foundation/branded-types';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { type ContractArtifact, encodeArguments } from '@aztec/stdlib/abi';
6
6
  import { PublicSimulatorConfig, type PublicTxResult } from '@aztec/stdlib/avm';
7
7
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
8
- import { Gas, GasFees } from '@aztec/stdlib/gas';
8
+ import { FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT, Gas, GasFees } from '@aztec/stdlib/gas';
9
9
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
10
10
  import { PublicCallRequest } from '@aztec/stdlib/kernel';
11
11
  import { GlobalVariables, PublicCallRequestWithCalldata, type Tx } from '@aztec/stdlib/tx';
@@ -112,6 +112,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
112
112
  feePayer: AztecAddress = sender,
113
113
  /* need some unique first nullifier for note-nonce computations */
114
114
  privateInsertions: TestPrivateInsertions = { nonRevertible: { nullifiers: [new Fr(420000 + this.txCount)] } },
115
+ gasLimits?: Gas,
115
116
  ): Promise<Tx> {
116
117
  const setupCallRequests = await asyncMap(setupCalls, call =>
117
118
  this.#createPubicCallRequestForCall(call, call.sender ?? sender),
@@ -131,9 +132,13 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
131
132
  teardownCallRequest,
132
133
  feePayer,
133
134
  /*gasUsedByPrivate*/ teardownCall
134
- ? new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT)
135
- : Gas.empty(),
135
+ ? new Gas(
136
+ FALLBACK_TEARDOWN_DA_GAS_LIMIT + TX_DA_GAS_OVERHEAD,
137
+ FALLBACK_TEARDOWN_L2_GAS_LIMIT + PUBLIC_TX_L2_GAS_OVERHEAD,
138
+ )
139
+ : new Gas(TX_DA_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD),
136
140
  defaultGlobals(),
141
+ gasLimits,
137
142
  );
138
143
  }
139
144
 
@@ -146,8 +151,9 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
146
151
  /* need some unique first nullifier for note-nonce computations */
147
152
  privateInsertions?: TestPrivateInsertions,
148
153
  txLabel: string = 'unlabeledTx',
154
+ gasLimits?: Gas,
149
155
  ): Promise<PublicTxResult> {
150
- const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions);
156
+ const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions, gasLimits);
151
157
 
152
158
  await this.setFeePayerBalance(feePayer);
153
159
 
@@ -161,6 +167,8 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
161
167
  }
162
168
  const avmResult = await this.simulator.simulate(tx, fullTxLabel);
163
169
 
170
+ await this.#recordBytecodeSizes(fullTxLabel, [...setupCalls, ...appCalls, ...(teardownCall ? [teardownCall] : [])]);
171
+
164
172
  // Something like this is often useful for debugging:
165
173
  //if (avmResult.revertReason) {
166
174
  // // resolve / enrich revert reason
@@ -190,8 +198,18 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
190
198
  teardownCall?: TestEnqueuedCall,
191
199
  feePayer?: AztecAddress,
192
200
  privateInsertions?: TestPrivateInsertions,
201
+ gasLimits?: Gas,
193
202
  ): Promise<PublicTxResult> {
194
- return await this.simulateTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions, txLabel);
203
+ return await this.simulateTx(
204
+ sender,
205
+ setupCalls,
206
+ appCalls,
207
+ teardownCall,
208
+ feePayer,
209
+ privateInsertions,
210
+ txLabel,
211
+ gasLimits,
212
+ );
195
213
  }
196
214
 
197
215
  /**
@@ -209,6 +227,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
209
227
  teardownCall?: TestEnqueuedCall,
210
228
  feePayer?: AztecAddress,
211
229
  privateInsertions?: TestPrivateInsertions,
230
+ gasLimits?: Gas,
212
231
  ): Promise<PublicTxResult> {
213
232
  return await this.simulateTxWithLabel(
214
233
  txLabel,
@@ -218,6 +237,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
218
237
  teardownCall,
219
238
  feePayer,
220
239
  privateInsertions,
240
+ gasLimits,
221
241
  );
222
242
  }
223
243
 
@@ -277,6 +297,27 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
277
297
 
278
298
  return new PublicCallRequestWithCalldata(request, calldata);
279
299
  }
300
+
301
+ // WARNING: Deduplicates by artifact name, so two different artifacts with the same name
302
+ // in a single tx would only record the first one's bytecode size.
303
+ async #recordBytecodeSizes(txLabel: string, calls: TestEnqueuedCall[]) {
304
+ const seenArtifactNames = new Set<string>();
305
+ for (const call of calls) {
306
+ const artifact = await this.contractDataSource.getContractArtifact(call.address);
307
+ if (!artifact || seenArtifactNames.has(artifact.name)) {
308
+ continue;
309
+ }
310
+ seenArtifactNames.add(artifact.name);
311
+ const instance = await this.contractDataSource.getContract(call.address);
312
+ if (!instance) {
313
+ continue;
314
+ }
315
+ const contractClass = await this.contractDataSource.getContractClass(instance.currentContractClassId);
316
+ if (contractClass) {
317
+ this.metrics.recordBytecodeSize(txLabel, artifact.name, contractClass.packedBytecode.length);
318
+ }
319
+ }
320
+ }
280
321
  }
281
322
 
282
323
  export function defaultGlobals() {