@aztec/simulator 0.67.1 → 0.68.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 (104) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +1 -1
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +3 -3
  4. package/dest/acvm/oracle/typed_oracle.d.ts +1 -1
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +3 -3
  7. package/dest/avm/avm_memory_types.d.ts +1 -1
  8. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  9. package/dest/avm/avm_memory_types.js +27 -27
  10. package/dest/avm/avm_simulator.d.ts.map +1 -1
  11. package/dest/avm/avm_simulator.js +6 -3
  12. package/dest/avm/avm_tree.d.ts +2 -1
  13. package/dest/avm/avm_tree.d.ts.map +1 -1
  14. package/dest/avm/avm_tree.js +6 -2
  15. package/dest/avm/fixtures/index.d.ts +2 -0
  16. package/dest/avm/fixtures/index.d.ts.map +1 -1
  17. package/dest/avm/fixtures/index.js +4 -4
  18. package/dest/avm/journal/journal.d.ts +16 -4
  19. package/dest/avm/journal/journal.d.ts.map +1 -1
  20. package/dest/avm/journal/journal.js +32 -14
  21. package/dest/avm/opcodes/conversion.d.ts +4 -4
  22. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  23. package/dest/avm/opcodes/conversion.js +22 -18
  24. package/dest/avm/test_utils.d.ts +1 -0
  25. package/dest/avm/test_utils.d.ts.map +1 -1
  26. package/dest/avm/test_utils.js +4 -1
  27. package/dest/client/client_execution_context.d.ts.map +1 -1
  28. package/dest/client/client_execution_context.js +2 -1
  29. package/dest/client/db_oracle.d.ts +7 -3
  30. package/dest/client/db_oracle.d.ts.map +1 -1
  31. package/dest/client/index.d.ts +1 -0
  32. package/dest/client/index.d.ts.map +1 -1
  33. package/dest/client/index.js +2 -1
  34. package/dest/client/view_data_oracle.d.ts +2 -2
  35. package/dest/client/view_data_oracle.d.ts.map +1 -1
  36. package/dest/client/view_data_oracle.js +5 -4
  37. package/dest/providers/acvm_wasm.js +2 -2
  38. package/dest/providers/acvm_wasm_with_blobs.d.ts +7 -0
  39. package/dest/providers/acvm_wasm_with_blobs.d.ts.map +1 -0
  40. package/dest/providers/acvm_wasm_with_blobs.js +15 -0
  41. package/dest/providers/index.d.ts +1 -1
  42. package/dest/providers/index.d.ts.map +1 -1
  43. package/dest/providers/index.js +2 -2
  44. package/dest/public/enqueued_call_side_effect_trace.d.ts +4 -3
  45. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  46. package/dest/public/enqueued_call_side_effect_trace.js +6 -5
  47. package/dest/public/execution.d.ts +2 -2
  48. package/dest/public/execution.d.ts.map +1 -1
  49. package/dest/public/execution.js +1 -1
  50. package/dest/public/executor_metrics.d.ts +2 -0
  51. package/dest/public/executor_metrics.d.ts.map +1 -1
  52. package/dest/public/executor_metrics.js +11 -1
  53. package/dest/public/fee_payment.d.ts.map +1 -1
  54. package/dest/public/fee_payment.js +4 -3
  55. package/dest/public/fixtures/index.d.ts +7 -6
  56. package/dest/public/fixtures/index.d.ts.map +1 -1
  57. package/dest/public/fixtures/index.js +23 -17
  58. package/dest/public/public_db_sources.d.ts.map +1 -1
  59. package/dest/public/public_db_sources.js +7 -6
  60. package/dest/public/public_processor.d.ts +7 -5
  61. package/dest/public/public_processor.d.ts.map +1 -1
  62. package/dest/public/public_processor.js +79 -65
  63. package/dest/public/public_processor_metrics.d.ts +10 -2
  64. package/dest/public/public_processor_metrics.d.ts.map +1 -1
  65. package/dest/public/public_processor_metrics.js +49 -2
  66. package/dest/public/public_tx_context.d.ts +5 -0
  67. package/dest/public/public_tx_context.d.ts.map +1 -1
  68. package/dest/public/public_tx_context.js +40 -20
  69. package/dest/public/public_tx_simulator.d.ts +2 -1
  70. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  71. package/dest/public/public_tx_simulator.js +35 -6
  72. package/dest/public/side_effect_trace_interface.d.ts +2 -1
  73. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  74. package/dest/public/transitional_adapters.d.ts.map +1 -1
  75. package/dest/public/transitional_adapters.js +2 -35
  76. package/package.json +12 -12
  77. package/src/acvm/oracle/oracle.ts +2 -2
  78. package/src/acvm/oracle/typed_oracle.ts +2 -2
  79. package/src/avm/avm_memory_types.ts +29 -27
  80. package/src/avm/avm_simulator.ts +4 -2
  81. package/src/avm/avm_tree.ts +6 -1
  82. package/src/avm/fixtures/index.ts +4 -2
  83. package/src/avm/journal/journal.ts +41 -8
  84. package/src/avm/opcodes/conversion.ts +21 -16
  85. package/src/avm/test_utils.ts +4 -0
  86. package/src/client/client_execution_context.ts +2 -0
  87. package/src/client/db_oracle.ts +8 -3
  88. package/src/client/index.ts +1 -0
  89. package/src/client/view_data_oracle.ts +6 -3
  90. package/src/providers/acvm_wasm.ts +1 -1
  91. package/src/providers/acvm_wasm_with_blobs.ts +25 -0
  92. package/src/providers/index.ts +1 -1
  93. package/src/public/enqueued_call_side_effect_trace.ts +8 -12
  94. package/src/public/execution.ts +1 -2
  95. package/src/public/executor_metrics.ts +13 -0
  96. package/src/public/fee_payment.ts +3 -2
  97. package/src/public/fixtures/index.ts +30 -22
  98. package/src/public/public_db_sources.ts +6 -5
  99. package/src/public/public_processor.ts +98 -79
  100. package/src/public/public_processor_metrics.ts +64 -2
  101. package/src/public/public_tx_context.ts +57 -21
  102. package/src/public/public_tx_simulator.ts +34 -6
  103. package/src/public/side_effect_trace_interface.ts +2 -1
  104. package/src/public/transitional_adapters.ts +0 -51
@@ -1,4 +1,4 @@
1
- import { MerkleTreeId } from '@aztec/circuit-types';
1
+ import { MerkleTreeId, type TxHash } from '@aztec/circuit-types';
2
2
  import {
3
3
  AztecAddress,
4
4
  CANONICAL_AUTH_REGISTRY_ADDRESS,
@@ -12,7 +12,13 @@ import {
12
12
  ROUTER_ADDRESS,
13
13
  SerializableContractInstance,
14
14
  } from '@aztec/circuits.js';
15
- import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
15
+ import {
16
+ computeNoteHashNonce,
17
+ computePublicDataTreeLeafSlot,
18
+ computeUniqueNoteHash,
19
+ siloNoteHash,
20
+ siloNullifier,
21
+ } from '@aztec/circuits.js/hash';
16
22
  import { Fr } from '@aztec/foundation/fields';
17
23
  import { jsonStringify } from '@aztec/foundation/json-rpc';
18
24
  import { createLogger } from '@aztec/foundation/log';
@@ -55,6 +61,7 @@ export class AvmPersistableStateManager {
55
61
  private readonly doMerkleOperations: boolean = false,
56
62
  /** Ephmeral forest for merkle tree operations */
57
63
  public merkleTrees: AvmEphemeralForest,
64
+ public readonly txHash: TxHash,
58
65
  ) {}
59
66
 
60
67
  /**
@@ -65,6 +72,7 @@ export class AvmPersistableStateManager {
65
72
  trace: PublicSideEffectTraceInterface,
66
73
  pendingSiloedNullifiers: Fr[],
67
74
  doMerkleOperations: boolean = false,
75
+ txHash: TxHash,
68
76
  ) {
69
77
  const parentNullifiers = NullifierManager.newWithPendingSiloedNullifiers(worldStateDB, pendingSiloedNullifiers);
70
78
  const ephemeralForest = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
@@ -75,6 +83,7 @@ export class AvmPersistableStateManager {
75
83
  /*nullifiers=*/ parentNullifiers.fork(),
76
84
  doMerkleOperations,
77
85
  ephemeralForest,
86
+ txHash,
78
87
  );
79
88
  }
80
89
 
@@ -85,6 +94,7 @@ export class AvmPersistableStateManager {
85
94
  worldStateDB: WorldStateDB,
86
95
  trace: PublicSideEffectTraceInterface,
87
96
  doMerkleOperations: boolean = false,
97
+ txHash: TxHash,
88
98
  ) {
89
99
  const ephemeralForest = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
90
100
  return new AvmPersistableStateManager(
@@ -94,6 +104,7 @@ export class AvmPersistableStateManager {
94
104
  /*nullifiers=*/ new NullifierManager(worldStateDB),
95
105
  /*doMerkleOperations=*/ doMerkleOperations,
96
106
  ephemeralForest,
107
+ txHash,
97
108
  );
98
109
  }
99
110
 
@@ -108,6 +119,7 @@ export class AvmPersistableStateManager {
108
119
  this.nullifiers.fork(),
109
120
  this.doMerkleOperations,
110
121
  this.merkleTrees.fork(),
122
+ this.txHash,
111
123
  );
112
124
  }
113
125
 
@@ -290,20 +302,41 @@ export class AvmPersistableStateManager {
290
302
  }
291
303
 
292
304
  /**
293
- * Write a note hash, trace the write.
305
+ * Write a raw note hash, silo it and make it unique, then trace the write.
294
306
  * @param noteHash - the unsiloed note hash to write
295
307
  */
296
308
  public writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): void {
297
- this.log.debug(`noteHashes(${contractAddress}) += @${noteHash}.`);
309
+ const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
310
+
311
+ this.writeSiloedNoteHash(siloedNoteHash);
312
+ }
313
+
314
+ /**
315
+ * Write a note hash, make it unique, trace the write.
316
+ * @param noteHash - the non unique note hash to write
317
+ */
318
+ public writeSiloedNoteHash(noteHash: Fr): void {
319
+ const txHash = Fr.fromBuffer(this.txHash.toBuffer());
320
+ const nonce = computeNoteHashNonce(txHash, this.trace.getNoteHashCount());
321
+ const uniqueNoteHash = computeUniqueNoteHash(nonce, noteHash);
322
+
323
+ this.writeUniqueNoteHash(uniqueNoteHash);
324
+ }
325
+
326
+ /**
327
+ * Write a note hash, trace the write.
328
+ * @param noteHash - the siloed unique hash to write
329
+ */
330
+ public writeUniqueNoteHash(noteHash: Fr): void {
331
+ this.log.debug(`noteHashes += @${noteHash}.`);
298
332
 
299
333
  if (this.doMerkleOperations) {
300
334
  // Should write a helper for this
301
335
  const leafIndex = new Fr(this.merkleTrees.treeMap.get(MerkleTreeId.NOTE_HASH_TREE)!.leafCount);
302
- const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
303
- const insertionPath = this.merkleTrees.appendNoteHash(siloedNoteHash);
304
- this.trace.traceNewNoteHash(contractAddress, noteHash, leafIndex, insertionPath);
336
+ const insertionPath = this.merkleTrees.appendNoteHash(noteHash);
337
+ this.trace.traceNewNoteHash(noteHash, leafIndex, insertionPath);
305
338
  } else {
306
- this.trace.traceNewNoteHash(contractAddress, noteHash);
339
+ this.trace.traceNewNoteHash(noteHash);
307
340
  }
308
341
  }
309
342
 
@@ -12,57 +12,62 @@ export class ToRadixBE extends Instruction {
12
12
  // Informs (de)serialization. See Instruction.deserialize.
13
13
  static readonly wireFormat: OperandType[] = [
14
14
  OperandType.UINT8, // Opcode
15
- OperandType.UINT8, // Indirect
15
+ OperandType.UINT16, // Indirect
16
16
  OperandType.UINT16, // src memory address
17
- OperandType.UINT16, // dst memory address
18
17
  OperandType.UINT16, // radix memory address
19
- OperandType.UINT16, // number of limbs (Immediate)
20
- OperandType.UINT8, // output is in "bits" mode (Immediate - Uint1 still takes up a whole byte)
18
+ OperandType.UINT16, // number of limbs address
19
+ OperandType.UINT16, // output is in "bits" mode memory address (boolean/Uint1 is stored)
20
+ OperandType.UINT16, // dst memory address
21
21
  ];
22
22
 
23
23
  constructor(
24
24
  private indirect: number,
25
25
  private srcOffset: number,
26
- private dstOffset: number,
27
26
  private radixOffset: number,
28
- private numLimbs: number,
29
- private outputBits: number, // effectively a bool
27
+ private numLimbsOffset: number,
28
+ private outputBitsOffset: number,
29
+ private dstOffset: number,
30
30
  ) {
31
31
  super();
32
32
  }
33
33
 
34
34
  public async execute(context: AvmContext): Promise<void> {
35
35
  const memory = context.machineState.memory.track(this.type);
36
- const operands = [this.srcOffset, this.dstOffset, this.radixOffset];
36
+ const operands = [this.srcOffset, this.radixOffset, this.numLimbsOffset, this.outputBitsOffset, this.dstOffset];
37
37
  const addressing = Addressing.fromWire(this.indirect, operands.length);
38
- const [srcOffset, dstOffset, radixOffset] = addressing.resolve(operands, memory);
39
- context.machineState.consumeGas(this.gasCost(this.numLimbs));
38
+ const [srcOffset, radixOffset, numLimbsOffset, outputBitsOffset, dstOffset] = addressing.resolve(operands, memory);
40
39
 
41
40
  // The radix gadget only takes in a Field
42
41
  memory.checkTag(TypeTag.FIELD, srcOffset);
43
42
  memory.checkTag(TypeTag.UINT32, radixOffset);
43
+ memory.checkTag(TypeTag.UINT32, numLimbsOffset);
44
+ memory.checkTag(TypeTag.UINT1, outputBitsOffset);
45
+
46
+ const numLimbs = memory.get(numLimbsOffset).toNumber();
47
+ context.machineState.consumeGas(this.gasCost(numLimbs));
48
+ const outputBits = memory.get(outputBitsOffset).toNumber();
44
49
 
45
50
  let value: bigint = memory.get(srcOffset).toBigInt();
46
51
  const radix: bigint = memory.get(radixOffset).toBigInt();
47
- if (this.numLimbs < 1) {
48
- throw new InstructionExecutionError(`ToRadixBE instruction's numLimbs should be > 0 (was ${this.numLimbs})`);
52
+ if (numLimbs < 1) {
53
+ throw new InstructionExecutionError(`ToRadixBE instruction's numLimbs should be > 0 (was ${numLimbs})`);
49
54
  }
50
55
  if (radix > 256) {
51
56
  throw new InstructionExecutionError(`ToRadixBE instruction's radix should be <= 256 (was ${radix})`);
52
57
  }
53
58
  const radixBN: bigint = BigInt(radix);
54
- const limbArray = new Array(this.numLimbs);
59
+ const limbArray = new Array(numLimbs);
55
60
 
56
- for (let i = this.numLimbs - 1; i >= 0; i--) {
61
+ for (let i = numLimbs - 1; i >= 0; i--) {
57
62
  const limb = value % radixBN;
58
63
  limbArray[i] = limb;
59
64
  value /= radixBN;
60
65
  }
61
66
 
62
- const outputType = this.outputBits != 0 ? Uint1 : Uint8;
67
+ const outputType = outputBits != 0 ? Uint1 : Uint8;
63
68
  const res = limbArray.map(byte => new outputType(byte));
64
69
  memory.setSlice(dstOffset, res);
65
70
 
66
- memory.assert({ reads: 2, writes: this.numLimbs, addressing });
71
+ memory.assert({ reads: 4, writes: numLimbs, addressing });
67
72
  }
68
73
  }
@@ -28,6 +28,10 @@ export function mockStorageRead(worldStateDB: WorldStateDB, value: Fr) {
28
28
  (worldStateDB as jest.Mocked<WorldStateDB>).storageRead.mockResolvedValue(value);
29
29
  }
30
30
 
31
+ export function mockNoteHashCount(mockedTrace: PublicSideEffectTraceInterface, count: number) {
32
+ (mockedTrace as jest.Mocked<PublicSideEffectTraceInterface>).getNoteHashCount.mockReturnValue(count);
33
+ }
34
+
31
35
  export function mockStorageReadWithMap(worldStateDB: WorldStateDB, mockedStorage: Map<bigint, Fr>) {
32
36
  (worldStateDB as jest.Mocked<WorldStateDB>).storageRead.mockImplementation((_address, slot) =>
33
37
  Promise.resolve(mockedStorage.get(slot.toBigInt()) ?? Fr.ZERO),
@@ -565,5 +565,7 @@ export class ClientExecutionContext extends ViewDataOracle {
565
565
  for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) {
566
566
  await this.db.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient));
567
567
  }
568
+
569
+ await this.db.removeNullifiedNotes(this.contractAddress);
568
570
  }
569
571
  }
@@ -198,21 +198,21 @@ export interface DBOracle extends CommitmentsDB {
198
198
  getBlockNumber(): Promise<number>;
199
199
 
200
200
  /**
201
- * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivpsk_m of the sender must be known.
201
+ * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
202
202
  * Includes the next index to be used used for tagging with this secret.
203
203
  * @param contractAddress - The contract address to silo the secret for
204
204
  * @param sender - The address sending the note
205
205
  * @param recipient - The address receiving the note
206
206
  * @returns A tagging secret that can be used to tag notes.
207
207
  */
208
- getAppTaggingSecretAsSender(
208
+ getIndexedTaggingSecretAsSender(
209
209
  contractAddress: AztecAddress,
210
210
  sender: AztecAddress,
211
211
  recipient: AztecAddress,
212
212
  ): Promise<IndexedTaggingSecret>;
213
213
 
214
214
  /**
215
- * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivpsk_m of the sender must be known.
215
+ * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
216
216
  * @param contractAddress - The contract address to silo the secret for
217
217
  * @param sender - The address sending the note
218
218
  * @param recipient - The address receiving the note
@@ -242,4 +242,9 @@ export interface DBOracle extends CommitmentsDB {
242
242
  * @param recipient - The recipient of the logs.
243
243
  */
244
244
  processTaggedLogs(logs: TxScopedL2Log[], recipient: AztecAddress): Promise<void>;
245
+
246
+ /**
247
+ * Removes all of a contract's notes that have been nullified from the note database.
248
+ */
249
+ removeNullifiedNotes(contractAddress: AztecAddress): Promise<void>;
245
250
  }
@@ -3,3 +3,4 @@ export * from './db_oracle.js';
3
3
  export * from './pick_notes.js';
4
4
  export * from './execution_note_cache.js';
5
5
  export { extractPrivateCircuitPublicInputs } from './private_execution.js';
6
+ export { WASMSimulator } from '../providers/acvm_wasm.js';
@@ -296,16 +296,16 @@ export class ViewDataOracle extends TypedOracle {
296
296
  /**
297
297
  * Returns the tagging secret for a given sender and recipient pair, siloed to the current contract address.
298
298
  * Includes the next index to be used used for tagging with this secret.
299
- * For this to work, the ivpsk_m of the sender must be known.
299
+ * For this to work, the ivsk_m of the sender must be known.
300
300
  * @param sender - The address sending the note
301
301
  * @param recipient - The address receiving the note
302
302
  * @returns A tagging secret that can be used to tag notes.
303
303
  */
304
- public override async getAppTaggingSecretAsSender(
304
+ public override async getIndexedTaggingSecretAsSender(
305
305
  sender: AztecAddress,
306
306
  recipient: AztecAddress,
307
307
  ): Promise<IndexedTaggingSecret> {
308
- return await this.db.getAppTaggingSecretAsSender(this.contractAddress, sender, recipient);
308
+ return await this.db.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient);
309
309
  }
310
310
 
311
311
  public override async syncNotes() {
@@ -314,8 +314,11 @@ export class ViewDataOracle extends TypedOracle {
314
314
  await this.aztecNode.getBlockNumber(),
315
315
  this.scopes,
316
316
  );
317
+
317
318
  for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) {
318
319
  await this.db.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient));
319
320
  }
321
+
322
+ await this.db.removeNullifiedNotes(this.contractAddress);
320
323
  }
321
324
  }
@@ -1,4 +1,4 @@
1
- import { foreignCallHandler } from '@aztec/noir-protocol-circuits-types';
1
+ import { foreignCallHandler } from '@aztec/noir-protocol-circuits-types/client';
2
2
  import { type NoirCompiledCircuit } from '@aztec/types/noir';
3
3
 
4
4
  import { executeCircuit } from '@noir-lang/acvm_js';
@@ -0,0 +1,25 @@
1
+ import { foreignCallHandler } from '@aztec/noir-protocol-circuits-types';
2
+ import { type NoirCompiledCircuit } from '@aztec/types/noir';
3
+
4
+ import { executeCircuit } from '@noir-lang/acvm_js';
5
+ import { type WitnessMap } from '@noir-lang/types';
6
+
7
+ import { type SimulationProvider } from './simulation_provider.js';
8
+
9
+ export class WASMSimulatorWithBlobs implements SimulationProvider {
10
+ async simulateCircuit(input: WitnessMap, compiledCircuit: NoirCompiledCircuit): Promise<WitnessMap> {
11
+ // Execute the circuit on those initial witness values
12
+ //
13
+ // Decode the bytecode from base64 since the acvm does not know about base64 encoding
14
+ const decodedBytecode = Buffer.from(compiledCircuit.bytecode, 'base64');
15
+ //
16
+ // Execute the circuit
17
+ const _witnessMap = await executeCircuit(
18
+ decodedBytecode,
19
+ input,
20
+ foreignCallHandler, // handle calls to debug_log and evaluate_blobs mock
21
+ );
22
+
23
+ return _witnessMap;
24
+ }
25
+ }
@@ -1,4 +1,4 @@
1
1
  export * from './acvm_native.js';
2
- export * from './acvm_wasm.js';
2
+ export * from './acvm_wasm_with_blobs.js';
3
3
  export * from './simulation_provider.js';
4
4
  export * from './factory.js';
@@ -42,7 +42,6 @@ import {
42
42
  PublicDataWrite,
43
43
  ScopedL2ToL1Message,
44
44
  ScopedLogHash,
45
- type ScopedNoteHash,
46
45
  SerializableContractInstance,
47
46
  type TreeSnapshots,
48
47
  } from '@aztec/circuits.js';
@@ -74,7 +73,7 @@ export type SideEffects = {
74
73
  enqueuedCalls: PublicCallRequest[];
75
74
 
76
75
  publicDataWrites: PublicDataUpdateRequest[];
77
- noteHashes: ScopedNoteHash[];
76
+ noteHashes: NoteHash[];
78
77
  nullifiers: Nullifier[];
79
78
  l2ToL1Msgs: ScopedL2ToL1Message[];
80
79
 
@@ -111,7 +110,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
111
110
  private publicDataWrites: PublicDataUpdateRequest[] = [];
112
111
  private protocolPublicDataWritesLength: number = 0;
113
112
  private userPublicDataWritesLength: number = 0;
114
- private noteHashes: ScopedNoteHash[] = [];
113
+ private noteHashes: NoteHash[] = [];
115
114
  private nullifiers: Nullifier[] = [];
116
115
  private l2ToL1Messages: ScopedL2ToL1Message[] = [];
117
116
  private unencryptedLogs: UnencryptedL2Log[] = [];
@@ -194,6 +193,10 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
194
193
  this.sideEffectCounter++;
195
194
  }
196
195
 
196
+ public getNoteHashCount() {
197
+ return this.previousSideEffectArrayLengths.noteHashes + this.noteHashes.length;
198
+ }
199
+
197
200
  public tracePublicStorageRead(
198
201
  contractAddress: AztecAddress,
199
202
  slot: Fr,
@@ -272,19 +275,12 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
272
275
  // NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes)
273
276
  }
274
277
 
275
- public traceNewNoteHash(
276
- contractAddress: AztecAddress,
277
- noteHash: Fr,
278
- leafIndex: Fr = Fr.zero(),
279
- path: Fr[] = emptyNoteHashPath(),
280
- ) {
278
+ public traceNewNoteHash(noteHash: Fr, leafIndex: Fr = Fr.zero(), path: Fr[] = emptyNoteHashPath()) {
281
279
  if (this.noteHashes.length + this.previousSideEffectArrayLengths.noteHashes >= MAX_NOTE_HASHES_PER_TX) {
282
280
  throw new SideEffectLimitReachedError('note hash', MAX_NOTE_HASHES_PER_TX);
283
281
  }
284
282
 
285
- // TODO(dbanks12): make unique and silo instead of scoping
286
- //const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
287
- this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter).scope(contractAddress));
283
+ this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter));
288
284
  this.log.debug(`NEW_NOTE_HASH cnt: ${this.sideEffectCounter}`);
289
285
  this.avmCircuitHints.noteHashWrites.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
290
286
  this.incrementSideEffectCounter();
@@ -20,7 +20,6 @@ import {
20
20
  RevertCode,
21
21
  type ScopedL2ToL1Message,
22
22
  type ScopedLogHash,
23
- type ScopedNoteHash,
24
23
  type TreeLeafReadRequest,
25
24
  } from '@aztec/circuits.js';
26
25
  import { computeVarArgsHash } from '@aztec/circuits.js/hash';
@@ -29,7 +28,7 @@ export interface PublicSideEffects {
29
28
  /** The contract storage update requests performed. */
30
29
  publicDataWrites: PublicDataUpdateRequest[];
31
30
  /** The new note hashes to be inserted into the note hashes tree. */
32
- noteHashes: ScopedNoteHash[];
31
+ noteHashes: NoteHash[];
33
32
  /** The new nullifiers to be inserted into the nullifier tree. */
34
33
  nullifiers: Nullifier[];
35
34
  /** The new l2 to l1 messages generated to be inserted into the messages tree. */
@@ -13,6 +13,7 @@ export class ExecutorMetrics {
13
13
  private fnCount: UpDownCounter;
14
14
  private fnDuration: Histogram;
15
15
  private manaPerSecond: Histogram;
16
+ private privateEffectsInsertions: Histogram;
16
17
 
17
18
  constructor(client: TelemetryClient, name = 'PublicExecutor') {
18
19
  this.tracer = client.getTracer(name);
@@ -33,6 +34,12 @@ export class ExecutorMetrics {
33
34
  unit: 'mana/s',
34
35
  valueType: ValueType.INT,
35
36
  });
37
+
38
+ this.privateEffectsInsertions = meter.createHistogram(Metrics.PUBLIC_EXECUTION_PRIVATE_EFFECTS_INSERTION, {
39
+ description: 'Private effects insertion time',
40
+ unit: 'us',
41
+ valueType: ValueType.INT,
42
+ });
36
43
  }
37
44
 
38
45
  recordFunctionSimulation(durationMs: number, manaUsed: number, fnName: string) {
@@ -55,4 +62,10 @@ export class ExecutorMetrics {
55
62
  [Attributes.OK]: false,
56
63
  });
57
64
  }
65
+
66
+ recordPrivateEffectsInsertion(durationUs: number, type: 'revertible' | 'non-revertible') {
67
+ this.privateEffectsInsertions.record(Math.ceil(durationUs), {
68
+ [Attributes.REVERTIBILITY]: type,
69
+ });
70
+ }
58
71
  }
@@ -1,13 +1,14 @@
1
1
  import { computePublicDataTreeLeafSlot, deriveStorageSlotInMap } from '@aztec/circuits.js/hash';
2
2
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
- import { ProtocolContractAddress, ProtocolContractArtifact } from '@aztec/protocol-contracts';
4
+ import { ProtocolContractAddress } from '@aztec/protocol-contracts';
5
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
5
6
 
6
7
  /**
7
8
  * Computes the storage slot within the Fee Juice contract for the balance of the fee payer.
8
9
  */
9
10
  export function computeFeePayerBalanceStorageSlot(feePayer: AztecAddress) {
10
- return deriveStorageSlotInMap(ProtocolContractArtifact.FeeJuice.storageLayout.balances.slot, feePayer);
11
+ return deriveStorageSlotInMap(FeeJuiceArtifact.storageLayout.balances.slot, feePayer);
11
12
  }
12
13
 
13
14
  /**
@@ -4,6 +4,7 @@ import {
4
4
  BlockHeader,
5
5
  CallContext,
6
6
  type ContractClassPublic,
7
+ type ContractDataSource,
7
8
  type ContractInstanceWithAddress,
8
9
  DEFAULT_GAS_LIMIT,
9
10
  DEPLOYER_CONTRACT_ADDRESS,
@@ -29,7 +30,7 @@ import { type ContractArtifact, type FunctionArtifact } from '@aztec/foundation/
29
30
  import { AztecAddress } from '@aztec/foundation/aztec-address';
30
31
  import { Fr, Point } from '@aztec/foundation/fields';
31
32
  import { openTmpStore } from '@aztec/kv-store/lmdb';
32
- import { AvmTestContractArtifact } from '@aztec/noir-contracts.js';
33
+ import { AvmTestContractArtifact } from '@aztec/noir-contracts.js/AvmTest';
33
34
  import { PublicTxSimulator, WorldStateDB } from '@aztec/simulator';
34
35
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
35
36
  import { MerkleTrees } from '@aztec/world-state';
@@ -40,6 +41,7 @@ export async function simulateAvmTestContractGenerateCircuitInputs(
40
41
  functionName: string,
41
42
  calldata: Fr[] = [],
42
43
  expectRevert: boolean = false,
44
+ skipContractDeployments: boolean = false,
43
45
  assertionErrString?: string,
44
46
  ): Promise<AvmCircuitInputs> {
45
47
  const sender = AztecAddress.random();
@@ -52,21 +54,24 @@ export async function simulateAvmTestContractGenerateCircuitInputs(
52
54
 
53
55
  const telemetry = new NoopTelemetryClient();
54
56
  const merkleTrees = await (await MerkleTrees.new(openTmpStore(), telemetry)).fork();
55
- const contractDataSource = new MockedAvmTestContractDataSource();
57
+ const contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments);
56
58
  const worldStateDB = new WorldStateDB(merkleTrees, contractDataSource);
57
59
 
58
60
  const contractInstance = contractDataSource.contractInstance;
59
- const contractAddressNullifier = siloNullifier(
60
- AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
61
- contractInstance.address.toField(),
62
- );
63
- await merkleTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [contractAddressNullifier.toBuffer()], 0);
64
- // other contract address used by the bulk test's GETCONTRACTINSTANCE test
65
- const otherContractAddressNullifier = siloNullifier(
66
- AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
67
- contractDataSource.otherContractInstance.address.toField(),
68
- );
69
- await merkleTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [otherContractAddressNullifier.toBuffer()], 0);
61
+
62
+ if (!skipContractDeployments) {
63
+ const contractAddressNullifier = siloNullifier(
64
+ AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
65
+ contractInstance.address.toField(),
66
+ );
67
+ await merkleTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [contractAddressNullifier.toBuffer()], 0);
68
+ // other contract address used by the bulk test's GETCONTRACTINSTANCE test
69
+ const otherContractAddressNullifier = siloNullifier(
70
+ AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
71
+ contractDataSource.otherContractInstance.address.toField(),
72
+ );
73
+ await merkleTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [otherContractAddressNullifier.toBuffer()], 0);
74
+ }
70
75
 
71
76
  const simulator = new PublicTxSimulator(
72
77
  merkleTrees,
@@ -125,7 +130,7 @@ export function createTxForPublicCall(
125
130
  }
126
131
 
127
132
  const teardownGasLimits = isTeardown ? gasLimits : Gas.empty();
128
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty());
133
+ const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
129
134
  const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings);
130
135
  const constantData = new TxConstantData(BlockHeader.empty(), txContext, Fr.zero(), Fr.zero());
131
136
 
@@ -144,7 +149,7 @@ export function createTxForPublicCall(
144
149
  return tx;
145
150
  }
146
151
 
147
- export class MockedAvmTestContractDataSource {
152
+ export class MockedAvmTestContractDataSource implements ContractDataSource {
148
153
  private fnName = 'public_dispatch';
149
154
  private bytecode: Buffer;
150
155
  public fnSelector: FunctionSelector;
@@ -154,7 +159,7 @@ export class MockedAvmTestContractDataSource {
154
159
  private bytecodeCommitment: Fr;
155
160
  public otherContractInstance: ContractInstanceWithAddress;
156
161
 
157
- constructor() {
162
+ constructor(private noContractsDeployed: boolean = false) {
158
163
  this.bytecode = getAvmTestContractBytecode(this.fnName);
159
164
  this.fnSelector = getAvmTestContractFunctionSelector(this.fnName);
160
165
  this.publicFn = { bytecode: this.bytecode, selector: this.fnSelector };
@@ -198,12 +203,15 @@ export class MockedAvmTestContractDataSource {
198
203
  return Promise.resolve();
199
204
  }
200
205
 
201
- getContract(address: AztecAddress): Promise<ContractInstanceWithAddress> {
202
- if (address.equals(this.contractInstance.address)) {
203
- return Promise.resolve(this.contractInstance);
204
- } else {
205
- return Promise.resolve(this.otherContractInstance);
206
+ getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
207
+ if (!this.noContractsDeployed) {
208
+ if (address.equals(this.contractInstance.address)) {
209
+ return Promise.resolve(this.contractInstance);
210
+ } else if (address.equals(this.otherContractInstance.address)) {
211
+ return Promise.resolve(this.otherContractInstance);
212
+ }
206
213
  }
214
+ return Promise.resolve(undefined);
207
215
  }
208
216
 
209
217
  getContractClassIds(): Promise<Fr[]> {
@@ -218,7 +226,7 @@ export class MockedAvmTestContractDataSource {
218
226
  return Promise.resolve(this.fnName);
219
227
  }
220
228
 
221
- addContractArtifact(_address: AztecAddress, _contract: ContractArtifact): Promise<void> {
229
+ registerContractFunctionNames(_address: AztecAddress, _names: Record<string, string>): Promise<void> {
222
230
  return Promise.resolve();
223
231
  }
224
232
  }
@@ -22,7 +22,8 @@ import {
22
22
  import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
23
23
  import { createLogger } from '@aztec/foundation/log';
24
24
  import { Timer } from '@aztec/foundation/timer';
25
- import { ContractClassRegisteredEvent, ContractInstanceDeployedEvent } from '@aztec/protocol-contracts';
25
+ import { ContractClassRegisteredEvent } from '@aztec/protocol-contracts/class-registerer';
26
+ import { ContractInstanceDeployedEvent } from '@aztec/protocol-contracts/instance-deployer';
26
27
  import {
27
28
  type CommitmentsDB,
28
29
  MessageLoadOracleInputs,
@@ -207,7 +208,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
207
208
  nullifier: Fr,
208
209
  ): Promise<NullifierMembershipWitness | undefined> {
209
210
  const timer = new Timer();
210
- const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
211
+ const index = (await this.db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0];
211
212
  if (!index) {
212
213
  return undefined;
213
214
  }
@@ -240,7 +241,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
240
241
  ): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> {
241
242
  const timer = new Timer();
242
243
 
243
- const messageIndex = await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageHash);
244
+ const messageIndex = (await this.db.findLeafIndices(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [messageHash]))[0];
244
245
  if (messageIndex === undefined) {
245
246
  throw new Error(`No L1 to L2 message found for message hash ${messageHash.toString()}`);
246
247
  }
@@ -279,7 +280,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
279
280
 
280
281
  public async getCommitmentIndex(commitment: Fr): Promise<bigint | undefined> {
281
282
  const timer = new Timer();
282
- const index = await this.db.findLeafIndex(MerkleTreeId.NOTE_HASH_TREE, commitment);
283
+ const index = (await this.db.findLeafIndices(MerkleTreeId.NOTE_HASH_TREE, [commitment]))[0];
283
284
  this.logger.debug(`[DB] Fetched commitment index`, {
284
285
  eventName: 'public-db-access',
285
286
  duration: timer.ms(),
@@ -301,7 +302,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
301
302
 
302
303
  public async getNullifierIndex(nullifier: Fr): Promise<bigint | undefined> {
303
304
  const timer = new Timer();
304
- const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
305
+ const index = (await this.db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0];
305
306
  this.logger.debug(`[DB] Fetched nullifier index`, {
306
307
  eventName: 'public-db-access',
307
308
  duration: timer.ms(),