@aztec/simulator 0.64.0 → 0.65.1

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 (107) hide show
  1. package/dest/avm/avm_memory_types.d.ts +3 -1
  2. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  3. package/dest/avm/avm_memory_types.js +22 -24
  4. package/dest/avm/avm_simulator.d.ts +5 -1
  5. package/dest/avm/avm_simulator.d.ts.map +1 -1
  6. package/dest/avm/avm_simulator.js +16 -9
  7. package/dest/avm/avm_tree.d.ts +56 -7
  8. package/dest/avm/avm_tree.d.ts.map +1 -1
  9. package/dest/avm/avm_tree.js +155 -82
  10. package/dest/avm/errors.d.ts +19 -0
  11. package/dest/avm/errors.d.ts.map +1 -1
  12. package/dest/avm/errors.js +29 -1
  13. package/dest/avm/journal/journal.d.ts +8 -7
  14. package/dest/avm/journal/journal.d.ts.map +1 -1
  15. package/dest/avm/journal/journal.js +47 -29
  16. package/dest/avm/journal/nullifiers.d.ts +11 -58
  17. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  18. package/dest/avm/journal/nullifiers.js +27 -107
  19. package/dest/avm/opcodes/contract.d.ts +2 -2
  20. package/dest/avm/opcodes/contract.d.ts.map +1 -1
  21. package/dest/avm/opcodes/contract.js +4 -4
  22. package/dest/avm/opcodes/control_flow.d.ts +2 -2
  23. package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
  24. package/dest/avm/opcodes/control_flow.js +4 -4
  25. package/dest/avm/opcodes/environment_getters.d.ts +2 -2
  26. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  27. package/dest/avm/opcodes/environment_getters.js +4 -4
  28. package/dest/avm/opcodes/instruction.d.ts +1 -1
  29. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  30. package/dest/avm/opcodes/instruction.js +1 -1
  31. package/dest/avm/opcodes/memory.d.ts +4 -4
  32. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  33. package/dest/avm/opcodes/memory.js +17 -13
  34. package/dest/avm/opcodes/misc.d.ts +2 -2
  35. package/dest/avm/opcodes/misc.d.ts.map +1 -1
  36. package/dest/avm/opcodes/misc.js +4 -4
  37. package/dest/avm/serialization/buffer_cursor.d.ts +2 -0
  38. package/dest/avm/serialization/buffer_cursor.d.ts.map +1 -1
  39. package/dest/avm/serialization/buffer_cursor.js +8 -3
  40. package/dest/avm/serialization/bytecode_serialization.d.ts +1 -0
  41. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  42. package/dest/avm/serialization/bytecode_serialization.js +27 -13
  43. package/dest/avm/serialization/instruction_serialization.d.ts +1 -0
  44. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  45. package/dest/avm/serialization/instruction_serialization.js +9 -6
  46. package/dest/avm/test_utils.d.ts.map +1 -1
  47. package/dest/avm/test_utils.js +3 -2
  48. package/dest/common/errors.d.ts.map +1 -1
  49. package/dest/common/errors.js +3 -2
  50. package/dest/public/dual_side_effect_trace.d.ts +2 -2
  51. package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
  52. package/dest/public/dual_side_effect_trace.js +7 -7
  53. package/dest/public/enqueued_call_side_effect_trace.d.ts +8 -23
  54. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  55. package/dest/public/enqueued_call_side_effect_trace.js +31 -92
  56. package/dest/public/executor_metrics.d.ts +4 -2
  57. package/dest/public/executor_metrics.d.ts.map +1 -1
  58. package/dest/public/executor_metrics.js +20 -3
  59. package/dest/public/fixtures/index.d.ts.map +1 -1
  60. package/dest/public/fixtures/index.js +66 -35
  61. package/dest/public/public_db_sources.d.ts +3 -1
  62. package/dest/public/public_db_sources.d.ts.map +1 -1
  63. package/dest/public/public_db_sources.js +26 -11
  64. package/dest/public/public_processor.d.ts.map +1 -1
  65. package/dest/public/public_processor.js +12 -5
  66. package/dest/public/public_tx_context.d.ts +5 -6
  67. package/dest/public/public_tx_context.d.ts.map +1 -1
  68. package/dest/public/public_tx_context.js +19 -17
  69. package/dest/public/public_tx_simulator.d.ts +13 -2
  70. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  71. package/dest/public/public_tx_simulator.js +263 -217
  72. package/dest/public/side_effect_trace.d.ts +2 -2
  73. package/dest/public/side_effect_trace.d.ts.map +1 -1
  74. package/dest/public/side_effect_trace.js +8 -6
  75. package/dest/public/side_effect_trace_interface.d.ts +2 -2
  76. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  77. package/dest/public/transitional_adapters.d.ts.map +1 -1
  78. package/dest/public/transitional_adapters.js +2 -6
  79. package/package.json +9 -9
  80. package/src/avm/avm_memory_types.ts +26 -24
  81. package/src/avm/avm_simulator.ts +20 -13
  82. package/src/avm/avm_tree.ts +196 -93
  83. package/src/avm/errors.ts +31 -0
  84. package/src/avm/journal/journal.ts +61 -47
  85. package/src/avm/journal/nullifiers.ts +29 -121
  86. package/src/avm/opcodes/contract.ts +2 -2
  87. package/src/avm/opcodes/control_flow.ts +2 -2
  88. package/src/avm/opcodes/environment_getters.ts +2 -2
  89. package/src/avm/opcodes/instruction.ts +1 -1
  90. package/src/avm/opcodes/memory.ts +15 -10
  91. package/src/avm/opcodes/misc.ts +2 -2
  92. package/src/avm/serialization/buffer_cursor.ts +9 -3
  93. package/src/avm/serialization/bytecode_serialization.ts +29 -13
  94. package/src/avm/serialization/instruction_serialization.ts +12 -6
  95. package/src/avm/test_utils.ts +9 -1
  96. package/src/common/errors.ts +2 -1
  97. package/src/public/dual_side_effect_trace.ts +6 -30
  98. package/src/public/enqueued_call_side_effect_trace.ts +35 -154
  99. package/src/public/executor_metrics.ts +23 -1
  100. package/src/public/fixtures/index.ts +97 -43
  101. package/src/public/public_db_sources.ts +29 -15
  102. package/src/public/public_processor.ts +11 -4
  103. package/src/public/public_tx_context.ts +21 -23
  104. package/src/public/public_tx_simulator.ts +45 -8
  105. package/src/public/side_effect_trace.ts +7 -9
  106. package/src/public/side_effect_trace_interface.ts +2 -4
  107. package/src/public/transitional_adapters.ts +0 -11
@@ -8,7 +8,6 @@ import {
8
8
  AvmEnqueuedCallHint,
9
9
  AvmExecutionHints,
10
10
  AvmExternalCallHint,
11
- AvmKeyValueHint,
12
11
  AvmNullifierReadTreeHint,
13
12
  AvmNullifierWriteTreeHint,
14
13
  AvmPublicDataReadTreeHint,
@@ -23,14 +22,9 @@ import {
23
22
  L2ToL1Message,
24
23
  LogHash,
25
24
  MAX_ENQUEUED_CALLS_PER_TX,
26
- MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX,
27
25
  MAX_L2_TO_L1_MSGS_PER_TX,
28
26
  MAX_NOTE_HASHES_PER_TX,
29
- MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
30
27
  MAX_NULLIFIERS_PER_TX,
31
- MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
32
- MAX_NULLIFIER_READ_REQUESTS_PER_TX,
33
- MAX_PUBLIC_DATA_READS_PER_TX,
34
28
  MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
35
29
  MAX_UNENCRYPTED_LOGS_PER_TX,
36
30
  NOTE_HASH_TREE_HEIGHT,
@@ -42,22 +36,19 @@ import {
42
36
  PrivateToAvmAccumulatedData,
43
37
  PrivateToAvmAccumulatedDataArrayLengths,
44
38
  PublicCallRequest,
45
- PublicDataRead,
46
39
  PublicDataTreeLeafPreimage,
47
40
  PublicDataUpdateRequest,
48
41
  PublicDataWrite,
49
- ReadRequest,
50
42
  ScopedL2ToL1Message,
51
43
  ScopedLogHash,
52
44
  type ScopedNoteHash,
53
- type ScopedReadRequest,
54
45
  SerializableContractInstance,
55
- TreeLeafReadRequest,
56
46
  type TreeSnapshots,
57
47
  } from '@aztec/circuits.js';
58
- import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js/hash';
48
+ import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
59
49
  import { padArrayEnd } from '@aztec/foundation/collection';
60
50
  import { Fr } from '@aztec/foundation/fields';
51
+ import { jsonStringify } from '@aztec/foundation/json-rpc';
61
52
  import { createDebugLogger } from '@aztec/foundation/log';
62
53
 
63
54
  import { assert } from 'console';
@@ -81,17 +72,9 @@ const emptyL1ToL2MessagePath = () => new Array(L1_TO_L2_MSG_TREE_HEIGHT).fill(Fr
81
72
  export type SideEffects = {
82
73
  enqueuedCalls: PublicCallRequest[];
83
74
 
84
- publicDataReads: PublicDataRead[];
85
75
  publicDataWrites: PublicDataUpdateRequest[];
86
-
87
- noteHashReadRequests: TreeLeafReadRequest[];
88
76
  noteHashes: ScopedNoteHash[];
89
-
90
- nullifierReadRequests: ScopedReadRequest[];
91
- nullifierNonExistentReadRequests: ScopedReadRequest[];
92
77
  nullifiers: Nullifier[];
93
-
94
- l1ToL2MsgReadRequests: TreeLeafReadRequest[];
95
78
  l2ToL1Msgs: ScopedL2ToL1Message[];
96
79
 
97
80
  unencryptedLogs: UnencryptedL2Log[];
@@ -100,24 +83,15 @@ export type SideEffects = {
100
83
 
101
84
  export class SideEffectArrayLengths {
102
85
  constructor(
103
- public readonly publicDataReads: number,
104
86
  public readonly publicDataWrites: number,
105
-
106
- public readonly noteHashReadRequests: number,
107
87
  public readonly noteHashes: number,
108
-
109
- public readonly nullifierReadRequests: number,
110
- public readonly nullifierNonExistentReadRequests: number,
111
88
  public readonly nullifiers: number,
112
-
113
- public readonly l1ToL2MsgReadRequests: number,
114
89
  public readonly l2ToL1Msgs: number,
115
-
116
90
  public readonly unencryptedLogs: number,
117
91
  ) {}
118
92
 
119
93
  static empty() {
120
- return new this(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
94
+ return new this(0, 0, 0, 0, 0);
121
95
  }
122
96
  }
123
97
 
@@ -132,19 +106,10 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
132
106
 
133
107
  private enqueuedCalls: PublicCallRequest[] = [];
134
108
 
135
- private publicDataReads: PublicDataRead[] = [];
136
109
  private publicDataWrites: PublicDataUpdateRequest[] = [];
137
-
138
- private noteHashReadRequests: TreeLeafReadRequest[] = [];
139
110
  private noteHashes: ScopedNoteHash[] = [];
140
-
141
- private nullifierReadRequests: ScopedReadRequest[] = [];
142
- private nullifierNonExistentReadRequests: ScopedReadRequest[] = [];
143
111
  private nullifiers: Nullifier[] = [];
144
-
145
- private l1ToL2MsgReadRequests: TreeLeafReadRequest[] = [];
146
112
  private l2ToL1Messages: ScopedL2ToL1Message[] = [];
147
-
148
113
  private unencryptedLogs: UnencryptedL2Log[] = [];
149
114
  private unencryptedLogsHashes: ScopedLogHash[] = [];
150
115
 
@@ -170,15 +135,9 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
170
135
  return new PublicEnqueuedCallSideEffectTrace(
171
136
  this.sideEffectCounter,
172
137
  new SideEffectArrayLengths(
173
- this.previousSideEffectArrayLengths.publicDataReads + this.publicDataReads.length,
174
138
  this.previousSideEffectArrayLengths.publicDataWrites + this.publicDataWrites.length,
175
- this.previousSideEffectArrayLengths.noteHashReadRequests + this.noteHashReadRequests.length,
176
139
  this.previousSideEffectArrayLengths.noteHashes + this.noteHashes.length,
177
- this.previousSideEffectArrayLengths.nullifierReadRequests + this.nullifierReadRequests.length,
178
- this.previousSideEffectArrayLengths.nullifierNonExistentReadRequests +
179
- this.nullifierNonExistentReadRequests.length,
180
140
  this.previousSideEffectArrayLengths.nullifiers + this.nullifiers.length,
181
- this.previousSideEffectArrayLengths.l1ToL2MsgReadRequests + this.l1ToL2MsgReadRequests.length,
182
141
  this.previousSideEffectArrayLengths.l2ToL1Msgs + this.l2ToL1Messages.length,
183
142
  this.previousSideEffectArrayLengths.unencryptedLogs + this.unencryptedLogs.length,
184
143
  ),
@@ -193,23 +152,42 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
193
152
  );
194
153
  forkedTrace.alreadyMergedIntoParent = true;
195
154
 
196
- // TODO(dbanks12): accept & merge forked trace's hints!
197
155
  this.sideEffectCounter = forkedTrace.sideEffectCounter;
198
156
  this.enqueuedCalls.push(...forkedTrace.enqueuedCalls);
199
157
 
200
158
  if (!reverted) {
201
- this.publicDataReads.push(...forkedTrace.publicDataReads);
202
159
  this.publicDataWrites.push(...forkedTrace.publicDataWrites);
203
- this.noteHashReadRequests.push(...forkedTrace.noteHashReadRequests);
204
160
  this.noteHashes.push(...forkedTrace.noteHashes);
205
- this.nullifierReadRequests.push(...forkedTrace.nullifierReadRequests);
206
- this.nullifierNonExistentReadRequests.push(...forkedTrace.nullifierNonExistentReadRequests);
207
161
  this.nullifiers.push(...forkedTrace.nullifiers);
208
- this.l1ToL2MsgReadRequests.push(...forkedTrace.l1ToL2MsgReadRequests);
209
162
  this.l2ToL1Messages.push(...forkedTrace.l2ToL1Messages);
210
163
  this.unencryptedLogs.push(...forkedTrace.unencryptedLogs);
211
164
  this.unencryptedLogsHashes.push(...forkedTrace.unencryptedLogsHashes);
212
165
  }
166
+ this.mergeHints(forkedTrace);
167
+ }
168
+
169
+ private mergeHints(forkedTrace: this) {
170
+ this.avmCircuitHints.enqueuedCalls.items.push(...forkedTrace.avmCircuitHints.enqueuedCalls.items);
171
+
172
+ this.avmCircuitHints.storageValues.items.push(...forkedTrace.avmCircuitHints.storageValues.items);
173
+ this.avmCircuitHints.noteHashExists.items.push(...forkedTrace.avmCircuitHints.noteHashExists.items);
174
+ this.avmCircuitHints.nullifierExists.items.push(...forkedTrace.avmCircuitHints.nullifierExists.items);
175
+ this.avmCircuitHints.l1ToL2MessageExists.items.push(...forkedTrace.avmCircuitHints.l1ToL2MessageExists.items);
176
+
177
+ this.avmCircuitHints.externalCalls.items.push(...forkedTrace.avmCircuitHints.externalCalls.items);
178
+
179
+ this.avmCircuitHints.contractInstances.items.push(...forkedTrace.avmCircuitHints.contractInstances.items);
180
+ this.avmCircuitHints.contractBytecodeHints.items.push(...forkedTrace.avmCircuitHints.contractBytecodeHints.items);
181
+
182
+ this.avmCircuitHints.storageReadRequest.items.push(...forkedTrace.avmCircuitHints.storageReadRequest.items);
183
+ this.avmCircuitHints.storageUpdateRequest.items.push(...forkedTrace.avmCircuitHints.storageUpdateRequest.items);
184
+ this.avmCircuitHints.nullifierReadRequest.items.push(...forkedTrace.avmCircuitHints.nullifierReadRequest.items);
185
+ this.avmCircuitHints.nullifierWriteHints.items.push(...forkedTrace.avmCircuitHints.nullifierWriteHints.items);
186
+ this.avmCircuitHints.noteHashReadRequest.items.push(...forkedTrace.avmCircuitHints.noteHashReadRequest.items);
187
+ this.avmCircuitHints.noteHashWriteRequest.items.push(...forkedTrace.avmCircuitHints.noteHashWriteRequest.items);
188
+ this.avmCircuitHints.l1ToL2MessageReadRequest.items.push(
189
+ ...forkedTrace.avmCircuitHints.l1ToL2MessageReadRequest.items,
190
+ );
213
191
  }
214
192
 
215
193
  public getCounter() {
@@ -221,7 +199,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
221
199
  }
222
200
 
223
201
  public tracePublicStorageRead(
224
- contractAddress: AztecAddress,
202
+ _contractAddress: AztecAddress,
225
203
  slot: Fr,
226
204
  value: Fr,
227
205
  leafPreimage: PublicDataTreeLeafPreimage = PublicDataTreeLeafPreimage.empty(),
@@ -232,21 +210,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
232
210
  // if we have real merkle hint content, make sure the value matches the the provided preimage
233
211
  assert(leafPreimage.value.equals(value), 'Value mismatch when tracing in public data write');
234
212
  }
235
- // NOTE: exists and cached are unused for now but may be used for optimizations or kernel hints later
236
- if (
237
- this.publicDataReads.length + this.previousSideEffectArrayLengths.publicDataReads >=
238
- MAX_PUBLIC_DATA_READS_PER_TX
239
- ) {
240
- throw new SideEffectLimitReachedError('public data (contract storage) read', MAX_PUBLIC_DATA_READS_PER_TX);
241
- }
242
213
 
243
- const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
244
-
245
- this.publicDataReads.push(new PublicDataRead(leafSlot, value, this.sideEffectCounter));
246
-
247
- this.avmCircuitHints.storageValues.items.push(
248
- new AvmKeyValueHint(/*key=*/ new Fr(this.sideEffectCounter), /*value=*/ value),
249
- );
250
214
  this.avmCircuitHints.storageReadRequest.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path));
251
215
  this.log.debug(`SLOAD cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`);
252
216
  this.incrementSideEffectCounter();
@@ -296,22 +260,9 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
296
260
  _contractAddress: AztecAddress,
297
261
  noteHash: Fr,
298
262
  leafIndex: Fr,
299
- exists: boolean,
263
+ _exists: boolean,
300
264
  path: Fr[] = emptyNoteHashPath(),
301
265
  ) {
302
- // NOTE: contractAddress is unused because noteHash is an already-siloed leaf
303
- if (
304
- this.noteHashReadRequests.length + this.previousSideEffectArrayLengths.noteHashReadRequests >=
305
- MAX_NOTE_HASH_READ_REQUESTS_PER_TX
306
- ) {
307
- throw new SideEffectLimitReachedError('note hash read request', MAX_NOTE_HASH_READ_REQUESTS_PER_TX);
308
- }
309
-
310
- // note hash is already siloed here
311
- this.noteHashReadRequests.push(new TreeLeafReadRequest(noteHash, leafIndex));
312
- this.avmCircuitHints.noteHashExists.items.push(
313
- new AvmKeyValueHint(/*key=*/ new Fr(leafIndex), /*value=*/ exists ? Fr.ONE : Fr.ZERO),
314
- );
315
266
  // New Hinting
316
267
  this.avmCircuitHints.noteHashReadRequest.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
317
268
  // NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes)
@@ -336,29 +287,12 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
336
287
  }
337
288
 
338
289
  public traceNullifierCheck(
339
- contractAddress: AztecAddress,
340
- nullifier: Fr,
341
- exists: boolean,
290
+ _siloedNullifier: Fr,
291
+ _exists: boolean,
342
292
  lowLeafPreimage: NullifierLeafPreimage = NullifierLeafPreimage.empty(),
343
293
  lowLeafIndex: Fr = Fr.zero(),
344
294
  lowLeafPath: Fr[] = emptyNullifierPath(),
345
295
  ) {
346
- // NOTE: isPending and leafIndex are unused for now but may be used for optimizations or kernel hints later
347
- this.enforceLimitOnNullifierChecks();
348
-
349
- // TODO(dbanks12): use siloed nullifier instead of scoped once public kernel stops siloing
350
- // and once VM public inputs are meant to contain siloed nullifiers.
351
- //const siloedNullifier = siloNullifier(contractAddress, nullifier);
352
- const readRequest = new ReadRequest(nullifier, this.sideEffectCounter).scope(contractAddress);
353
- if (exists) {
354
- this.nullifierReadRequests.push(readRequest);
355
- } else {
356
- this.nullifierNonExistentReadRequests.push(readRequest);
357
- }
358
- this.avmCircuitHints.nullifierExists.items.push(
359
- new AvmKeyValueHint(/*key=*/ new Fr(this.sideEffectCounter), /*value=*/ new Fr(exists ? 1 : 0)),
360
- );
361
- // New Hints
362
296
  this.avmCircuitHints.nullifierReadRequest.items.push(
363
297
  new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath),
364
298
  );
@@ -367,8 +301,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
367
301
  }
368
302
 
369
303
  public traceNewNullifier(
370
- contractAddress: AztecAddress,
371
- nullifier: Fr,
304
+ siloedNullifier: Fr,
372
305
  lowLeafPreimage: NullifierLeafPreimage = NullifierLeafPreimage.empty(),
373
306
  lowLeafIndex: Fr = Fr.zero(),
374
307
  lowLeafPath: Fr[] = emptyNullifierPath(),
@@ -378,10 +311,8 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
378
311
  throw new SideEffectLimitReachedError('nullifier', MAX_NULLIFIERS_PER_TX);
379
312
  }
380
313
 
381
- const siloedNullifier = siloNullifier(contractAddress, nullifier);
382
314
  this.nullifiers.push(new Nullifier(siloedNullifier, this.sideEffectCounter, /*noteHash=*/ Fr.ZERO));
383
315
 
384
- // New hinting
385
316
  const lowLeafReadHint = new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
386
317
  this.avmCircuitHints.nullifierWriteHints.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath));
387
318
  this.log.debug(`NEW_NULLIFIER cnt: ${this.sideEffectCounter}`);
@@ -393,22 +324,9 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
393
324
  _contractAddress: AztecAddress,
394
325
  msgHash: Fr,
395
326
  msgLeafIndex: Fr,
396
- exists: boolean,
327
+ _exists: boolean,
397
328
  path: Fr[] = emptyL1ToL2MessagePath(),
398
329
  ) {
399
- // NOTE: contractAddress is unused because msgHash is an already-siloed leaf
400
- if (
401
- this.l1ToL2MsgReadRequests.length + this.previousSideEffectArrayLengths.l1ToL2MsgReadRequests >=
402
- MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX
403
- ) {
404
- throw new SideEffectLimitReachedError('l1 to l2 message read request', MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX);
405
- }
406
-
407
- this.l1ToL2MsgReadRequests.push(new TreeLeafReadRequest(msgHash, msgLeafIndex));
408
- this.avmCircuitHints.l1ToL2MessageExists.items.push(
409
- new AvmKeyValueHint(/*key=*/ new Fr(msgLeafIndex), /*value=*/ exists ? Fr.ONE : Fr.ZERO),
410
- );
411
- // New Hinting
412
330
  this.avmCircuitHints.l1ToL2MessageReadRequest.items.push(new AvmAppendTreeHint(msgLeafIndex, msgHash, path));
413
331
  }
414
332
 
@@ -450,8 +368,6 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
450
368
  exists: boolean,
451
369
  instance: SerializableContractInstance = SerializableContractInstance.default(),
452
370
  ) {
453
- this.enforceLimitOnNullifierChecks('(contract address nullifier from GETCONTRACTINSTANCE)');
454
-
455
371
  this.avmCircuitHints.contractInstances.items.push(
456
372
  new AvmContractInstanceHint(
457
373
  contractAddress,
@@ -495,9 +411,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
495
411
  new AvmContractBytecodeHints(bytecode, instance, contractClass),
496
412
  );
497
413
  this.log.debug(
498
- `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${JSON.stringify(
499
- contractInstance,
500
- )}`,
414
+ `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${jsonStringify(contractInstance)}`,
501
415
  );
502
416
  }
503
417
 
@@ -561,14 +475,9 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
561
475
  public getSideEffects(): SideEffects {
562
476
  return {
563
477
  enqueuedCalls: this.enqueuedCalls,
564
- publicDataReads: this.publicDataReads,
565
478
  publicDataWrites: this.publicDataWrites,
566
- noteHashReadRequests: this.noteHashReadRequests,
567
479
  noteHashes: this.noteHashes,
568
- nullifierReadRequests: this.nullifierReadRequests,
569
- nullifierNonExistentReadRequests: this.nullifierNonExistentReadRequests,
570
480
  nullifiers: this.nullifiers,
571
- l1ToL2MsgReadRequests: this.l1ToL2MsgReadRequests,
572
481
  l2ToL1Msgs: this.l2ToL1Messages,
573
482
  unencryptedLogs: this.unencryptedLogs,
574
483
  unencryptedLogsHashes: this.unencryptedLogsHashes,
@@ -690,32 +599,4 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
690
599
  ),
691
600
  );
692
601
  }
693
-
694
- private enforceLimitOnNullifierChecks(errorMsgOrigin: string = '') {
695
- // NOTE: Why error if _either_ limit was reached? If user code emits either an existent or non-existent
696
- // nullifier read request (NULLIFIEREXISTS, GETCONTRACTINSTANCE, *CALL), and one of the limits has been
697
- // reached (MAX_NULLIFIER_NON_EXISTENT_RRS vs MAX_NULLIFIER_RRS), but not the other, we must prevent the
698
- // sequencer from lying and saying "this nullifier exists, but MAX_NULLIFIER_RRS has been reached, so I'm
699
- // going to skip the read request and just revert instead" when the nullifier actually doesn't exist
700
- // (or vice versa). So, if either maximum has been reached, any nullifier-reading operation must error.
701
- if (
702
- this.nullifierReadRequests.length + this.previousSideEffectArrayLengths.nullifierReadRequests >=
703
- MAX_NULLIFIER_READ_REQUESTS_PER_TX
704
- ) {
705
- throw new SideEffectLimitReachedError(
706
- `nullifier read request ${errorMsgOrigin}`,
707
- MAX_NULLIFIER_READ_REQUESTS_PER_TX,
708
- );
709
- }
710
- if (
711
- this.nullifierNonExistentReadRequests.length +
712
- this.previousSideEffectArrayLengths.nullifierNonExistentReadRequests >=
713
- MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX
714
- ) {
715
- throw new SideEffectLimitReachedError(
716
- `nullifier non-existent read request ${errorMsgOrigin}`,
717
- MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
718
- );
719
- }
720
- }
721
602
  }
@@ -3,15 +3,20 @@ import {
3
3
  type Histogram,
4
4
  Metrics,
5
5
  type TelemetryClient,
6
+ type Tracer,
6
7
  type UpDownCounter,
7
8
  ValueType,
9
+ linearBuckets,
8
10
  } from '@aztec/telemetry-client';
9
11
 
10
12
  export class ExecutorMetrics {
13
+ public readonly tracer: Tracer;
11
14
  private fnCount: UpDownCounter;
12
15
  private fnDuration: Histogram;
16
+ private manaPerSecond: Histogram;
13
17
 
14
18
  constructor(client: TelemetryClient, name = 'PublicExecutor') {
19
+ this.tracer = client.getTracer(name);
15
20
  const meter = client.getMeter(name);
16
21
 
17
22
  this.fnCount = meter.createUpDownCounter(Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT, {
@@ -23,13 +28,30 @@ export class ExecutorMetrics {
23
28
  unit: 'ms',
24
29
  valueType: ValueType.INT,
25
30
  });
31
+
32
+ this.manaPerSecond = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_MANA_PER_SECOND, {
33
+ description: 'Mana used per second',
34
+ unit: 'mana/s',
35
+ valueType: ValueType.INT,
36
+ advice: {
37
+ explicitBucketBoundaries: linearBuckets(0, 10_000_000, 10),
38
+ },
39
+ });
26
40
  }
27
41
 
28
- recordFunctionSimulation(durationMs: number) {
42
+ recordFunctionSimulation(durationMs: number, manaUsed: number, fnName: string) {
29
43
  this.fnCount.add(1, {
30
44
  [Attributes.OK]: true,
45
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
46
+ [Attributes.MANA_USED]: manaUsed,
31
47
  });
32
48
  this.fnDuration.record(Math.ceil(durationMs));
49
+ if (durationMs > 0 && manaUsed > 0) {
50
+ const manaPerSecond = Math.round((manaUsed * 1000) / durationMs);
51
+ this.manaPerSecond.record(manaPerSecond, {
52
+ [Attributes.APP_CIRCUIT_NAME]: fnName,
53
+ });
54
+ }
33
55
  }
34
56
 
35
57
  recordFunctionSimulationFailure() {
@@ -2,7 +2,10 @@ import { PublicExecutionRequest, Tx } from '@aztec/circuit-types';
2
2
  import {
3
3
  type AvmCircuitInputs,
4
4
  CallContext,
5
+ type ContractClassPublic,
6
+ type ContractInstanceWithAddress,
5
7
  DEFAULT_GAS_LIMIT,
8
+ type FunctionSelector,
6
9
  Gas,
7
10
  GasFees,
8
11
  GasSettings,
@@ -17,21 +20,19 @@ import {
17
20
  SerializableContractInstance,
18
21
  TxConstantData,
19
22
  TxContext,
23
+ computePublicBytecodeCommitment,
20
24
  } from '@aztec/circuits.js';
21
25
  import { makeContractClassPublic, makeContractInstanceFromClassId } from '@aztec/circuits.js/testing';
26
+ import { type ContractArtifact } from '@aztec/foundation/abi';
22
27
  import { AztecAddress } from '@aztec/foundation/aztec-address';
23
28
  import { Fr, Point } from '@aztec/foundation/fields';
24
29
  import { openTmpStore } from '@aztec/kv-store/utils';
25
- import { PublicTxSimulator, type WorldStateDB } from '@aztec/simulator';
30
+ import { PublicTxSimulator, WorldStateDB } from '@aztec/simulator';
26
31
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
27
32
  import { MerkleTrees } from '@aztec/world-state';
28
33
 
29
- import { mock } from 'jest-mock-extended';
30
-
31
34
  import { getAvmTestContractBytecode, getAvmTestContractFunctionSelector } from '../../avm/fixtures/index.js';
32
35
 
33
- const TIMESTAMP = new Fr(99833);
34
-
35
36
  /**
36
37
  * If assertionErrString is set, we expect a (non exceptional halting) revert due to a failing assertion and
37
38
  * we check that the revert reason error contains this string. However, the circuit must correctly prove the
@@ -47,56 +48,31 @@ export async function simulateAvmTestContractGenerateCircuitInputs(
47
48
  calldata = [functionSelector.toField(), ...calldata];
48
49
 
49
50
  const globalVariables = GlobalVariables.empty();
50
- globalVariables.gasFees = GasFees.default();
51
- globalVariables.timestamp = TIMESTAMP;
51
+ globalVariables.gasFees = GasFees.empty();
52
+ globalVariables.timestamp = new Fr(99833);
52
53
 
53
- const worldStateDB = mock<WorldStateDB>();
54
54
  const telemetry = new NoopTelemetryClient();
55
55
  const merkleTrees = await (await MerkleTrees.new(openTmpStore(), telemetry)).fork();
56
- worldStateDB.getMerkleInterface.mockReturnValue(merkleTrees);
57
-
58
- // Top level contract call
59
- const bytecode = getAvmTestContractBytecode('public_dispatch');
60
- const dispatchSelector = getAvmTestContractFunctionSelector('public_dispatch');
61
- const publicFn: PublicFunction = { bytecode, selector: dispatchSelector };
62
- const contractClass = makeContractClassPublic(0, publicFn);
63
- const contractInstance = makeContractInstanceFromClassId(contractClass.id);
64
-
65
- // The values here should match those in `avm_simulator.test.ts`
66
- const instanceGet = new SerializableContractInstance({
67
- version: 1,
68
- salt: new Fr(0x123),
69
- deployer: new AztecAddress(new Fr(0x456)),
70
- contractClassId: new Fr(0x789),
71
- initializationHash: new Fr(0x101112),
72
- publicKeys: new PublicKeys(
73
- new Point(new Fr(0x131415), new Fr(0x161718), false),
74
- new Point(new Fr(0x192021), new Fr(0x222324), false),
75
- new Point(new Fr(0x252627), new Fr(0x282930), false),
76
- new Point(new Fr(0x313233), new Fr(0x343536), false),
77
- ),
78
- }).withAddress(contractInstance.address);
79
- worldStateDB.getContractInstance
80
- .mockResolvedValueOnce(contractInstance)
81
- .mockResolvedValueOnce(instanceGet) // test gets deployer
82
- .mockResolvedValueOnce(instanceGet) // test gets class id
83
- .mockResolvedValueOnce(instanceGet) // test gets init hash
84
- .mockResolvedValue(contractInstance);
85
- worldStateDB.getContractClass.mockResolvedValue(contractClass);
86
- worldStateDB.getBytecode.mockResolvedValue(bytecode);
87
-
88
- const storageValue = new Fr(5);
89
- worldStateDB.storageRead.mockResolvedValue(Promise.resolve(storageValue));
56
+ const contractDataSource = new MockedAvmTestContractDataSource();
57
+ const worldStateDB = new WorldStateDB(merkleTrees, contractDataSource);
58
+
59
+ const contractInstance = contractDataSource.contractInstance;
90
60
 
91
61
  const simulator = new PublicTxSimulator(
92
62
  merkleTrees,
93
63
  worldStateDB,
94
64
  new NoopTelemetryClient(),
95
65
  globalVariables,
66
+ /*realAvmProving=*/ true,
96
67
  /*doMerkleOperations=*/ true,
97
68
  );
98
69
 
99
- const callContext = new CallContext(sender, contractInstance.address, dispatchSelector, /*isStaticCall=*/ false);
70
+ const callContext = new CallContext(
71
+ sender,
72
+ contractInstance.address,
73
+ contractDataSource.fnSelector,
74
+ /*isStaticCall=*/ false,
75
+ );
100
76
  const executionRequest = new PublicExecutionRequest(callContext, calldata);
101
77
 
102
78
  const tx: Tx = createTxForPublicCall(executionRequest);
@@ -156,3 +132,81 @@ export function createTxForPublicCall(
156
132
 
157
133
  return tx;
158
134
  }
135
+
136
+ class MockedAvmTestContractDataSource {
137
+ private fnName = 'public_dispatch';
138
+ private bytecode: Buffer;
139
+ public fnSelector: FunctionSelector;
140
+ private publicFn: PublicFunction;
141
+ private contractClass: ContractClassPublic;
142
+ public contractInstance: ContractInstanceWithAddress;
143
+ private bytecodeCommitment: Fr;
144
+ private otherContractInstance: ContractInstanceWithAddress;
145
+
146
+ constructor() {
147
+ this.bytecode = getAvmTestContractBytecode(this.fnName);
148
+ this.fnSelector = getAvmTestContractFunctionSelector(this.fnName);
149
+ this.publicFn = { bytecode: this.bytecode, selector: this.fnSelector };
150
+ this.contractClass = makeContractClassPublic(0, this.publicFn);
151
+ this.contractInstance = makeContractInstanceFromClassId(this.contractClass.id);
152
+ this.bytecodeCommitment = computePublicBytecodeCommitment(this.bytecode);
153
+ // The values here should match those in `avm_simulator.test.ts`
154
+ this.otherContractInstance = new SerializableContractInstance({
155
+ version: 1,
156
+ salt: new Fr(0x123),
157
+ deployer: new AztecAddress(new Fr(0x456)),
158
+ contractClassId: new Fr(0x789),
159
+ initializationHash: new Fr(0x101112),
160
+ publicKeys: new PublicKeys(
161
+ new Point(new Fr(0x131415), new Fr(0x161718), false),
162
+ new Point(new Fr(0x192021), new Fr(0x222324), false),
163
+ new Point(new Fr(0x252627), new Fr(0x282930), false),
164
+ new Point(new Fr(0x313233), new Fr(0x343536), false),
165
+ ),
166
+ }).withAddress(this.contractInstance.address);
167
+ }
168
+
169
+ getPublicFunction(_address: AztecAddress, _selector: FunctionSelector): Promise<PublicFunction> {
170
+ return Promise.resolve(this.publicFn);
171
+ }
172
+
173
+ getBlockNumber(): Promise<number> {
174
+ throw new Error('Method not implemented.');
175
+ }
176
+
177
+ getContractClass(_id: Fr): Promise<ContractClassPublic> {
178
+ return Promise.resolve(this.contractClass);
179
+ }
180
+
181
+ getBytecodeCommitment(_id: Fr): Promise<Fr> {
182
+ return Promise.resolve(this.bytecodeCommitment);
183
+ }
184
+
185
+ addContractClass(_contractClass: ContractClassPublic): Promise<void> {
186
+ return Promise.resolve();
187
+ }
188
+
189
+ getContract(address: AztecAddress): Promise<ContractInstanceWithAddress> {
190
+ if (address.equals(this.contractInstance.address)) {
191
+ return Promise.resolve(this.contractInstance);
192
+ } else {
193
+ return Promise.resolve(this.otherContractInstance);
194
+ }
195
+ }
196
+
197
+ getContractClassIds(): Promise<Fr[]> {
198
+ throw new Error('Method not implemented.');
199
+ }
200
+
201
+ getContractArtifact(_address: AztecAddress): Promise<ContractArtifact | undefined> {
202
+ throw new Error('Method not implemented.');
203
+ }
204
+
205
+ getContractFunctionName(_address: AztecAddress, _selector: FunctionSelector): Promise<string> {
206
+ return Promise.resolve(this.fnName);
207
+ }
208
+
209
+ addContractArtifact(_address: AztecAddress, _contract: ContractArtifact): Promise<void> {
210
+ return Promise.resolve();
211
+ }
212
+ }
@@ -14,11 +14,12 @@ import {
14
14
  ContractInstanceDeployedEvent,
15
15
  type ContractInstanceWithAddress,
16
16
  Fr,
17
- FunctionSelector,
17
+ type FunctionSelector,
18
18
  type L1_TO_L2_MSG_TREE_HEIGHT,
19
19
  type NULLIFIER_TREE_HEIGHT,
20
20
  type NullifierLeafPreimage,
21
21
  type PublicDataTreeLeafPreimage,
22
+ computePublicBytecodeCommitment,
22
23
  } from '@aztec/circuits.js';
23
24
  import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
24
25
  import { createDebugLogger } from '@aztec/foundation/log';
@@ -38,11 +39,11 @@ import {
38
39
  export class ContractsDataSourcePublicDB implements PublicContractsDB {
39
40
  private instanceCache = new Map<string, ContractInstanceWithAddress>();
40
41
  private classCache = new Map<string, ContractClassPublic>();
42
+ private bytecodeCommitmentCache = new Map<string, Fr>();
41
43
 
42
44
  private log = createDebugLogger('aztec:sequencer:contracts-data-source');
43
45
 
44
46
  constructor(private dataSource: ContractDataSource) {}
45
-
46
47
  /**
47
48
  * Add new contracts from a transaction
48
49
  * @param tx - The transaction to add contracts from.
@@ -92,6 +93,31 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
92
93
  return this.classCache.get(contractClassId.toString()) ?? (await this.dataSource.getContractClass(contractClassId));
93
94
  }
94
95
 
96
+ public async getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
97
+ // Try and retrieve from cache
98
+ const key = contractClassId.toString();
99
+ const result = this.bytecodeCommitmentCache.get(key);
100
+ if (result !== undefined) {
101
+ return result;
102
+ }
103
+ // Now try from the store
104
+ const fromStore = await this.dataSource.getBytecodeCommitment(contractClassId);
105
+ if (fromStore !== undefined) {
106
+ this.bytecodeCommitmentCache.set(key, fromStore);
107
+ return fromStore;
108
+ }
109
+
110
+ // Not in either the store or the cache, build it here and cache
111
+ const contractClass = await this.getContractClass(contractClassId);
112
+ if (contractClass === undefined) {
113
+ return undefined;
114
+ }
115
+
116
+ const value = computePublicBytecodeCommitment(contractClass.packedBytecode);
117
+ this.bytecodeCommitmentCache.set(key, value);
118
+ return value;
119
+ }
120
+
95
121
  async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
96
122
  const instance = await this.getContractInstance(address);
97
123
  if (!instance) {
@@ -105,19 +131,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
105
131
  }
106
132
 
107
133
  public async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
108
- const artifact = await this.dataSource.getContractArtifact(address);
109
- if (!artifact) {
110
- return Promise.resolve(undefined);
111
- }
112
-
113
- const f = artifact.functions.find(f =>
114
- FunctionSelector.fromNameAndParameters(f.name, f.parameters).equals(selector),
115
- );
116
- if (!f) {
117
- return Promise.resolve(undefined);
118
- }
119
-
120
- return Promise.resolve(`${artifact.name}:${f.name}`);
134
+ return await this.dataSource.getContractFunctionName(address, selector);
121
135
  }
122
136
  }
123
137