@aztec/simulator 0.67.1 → 0.68.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 (143) 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 +45 -38
  10. package/dest/avm/avm_simulator.d.ts +1 -0
  11. package/dest/avm/avm_simulator.d.ts.map +1 -1
  12. package/dest/avm/avm_simulator.js +38 -18
  13. package/dest/avm/avm_tree.d.ts +2 -23
  14. package/dest/avm/avm_tree.d.ts.map +1 -1
  15. package/dest/avm/avm_tree.js +27 -82
  16. package/dest/avm/errors.d.ts +8 -1
  17. package/dest/avm/errors.d.ts.map +1 -1
  18. package/dest/avm/errors.js +13 -3
  19. package/dest/avm/fixtures/index.d.ts +2 -0
  20. package/dest/avm/fixtures/index.d.ts.map +1 -1
  21. package/dest/avm/fixtures/index.js +4 -4
  22. package/dest/avm/journal/journal.d.ts +15 -7
  23. package/dest/avm/journal/journal.d.ts.map +1 -1
  24. package/dest/avm/journal/journal.js +30 -22
  25. package/dest/avm/journal/nullifiers.d.ts +0 -4
  26. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  27. package/dest/avm/journal/nullifiers.js +1 -11
  28. package/dest/avm/journal/public_storage.d.ts +1 -49
  29. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  30. package/dest/avm/journal/public_storage.js +1 -19
  31. package/dest/avm/opcodes/addressing_mode.js +3 -3
  32. package/dest/avm/opcodes/conversion.d.ts +4 -4
  33. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  34. package/dest/avm/opcodes/conversion.js +22 -18
  35. package/dest/avm/opcodes/ec_add.d.ts.map +1 -1
  36. package/dest/avm/opcodes/ec_add.js +5 -4
  37. package/dest/avm/opcodes/external_calls.js +2 -2
  38. package/dest/avm/opcodes/hashing.d.ts.map +1 -1
  39. package/dest/avm/opcodes/hashing.js +5 -5
  40. package/dest/avm/opcodes/misc.d.ts.map +1 -1
  41. package/dest/avm/opcodes/misc.js +3 -3
  42. package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
  43. package/dest/avm/opcodes/multi_scalar_mul.js +9 -6
  44. package/dest/avm/test_utils.d.ts +1 -0
  45. package/dest/avm/test_utils.d.ts.map +1 -1
  46. package/dest/avm/test_utils.js +4 -1
  47. package/dest/client/client_execution_context.d.ts.map +1 -1
  48. package/dest/client/client_execution_context.js +2 -1
  49. package/dest/client/db_oracle.d.ts +7 -3
  50. package/dest/client/db_oracle.d.ts.map +1 -1
  51. package/dest/client/index.d.ts +1 -0
  52. package/dest/client/index.d.ts.map +1 -1
  53. package/dest/client/index.js +2 -1
  54. package/dest/client/view_data_oracle.d.ts +2 -2
  55. package/dest/client/view_data_oracle.d.ts.map +1 -1
  56. package/dest/client/view_data_oracle.js +5 -4
  57. package/dest/providers/acvm_wasm.js +2 -2
  58. package/dest/providers/acvm_wasm_with_blobs.d.ts +7 -0
  59. package/dest/providers/acvm_wasm_with_blobs.d.ts.map +1 -0
  60. package/dest/providers/acvm_wasm_with_blobs.js +15 -0
  61. package/dest/providers/index.d.ts +1 -1
  62. package/dest/providers/index.d.ts.map +1 -1
  63. package/dest/providers/index.js +2 -2
  64. package/dest/public/bytecode_errors.d.ts +4 -0
  65. package/dest/public/bytecode_errors.d.ts.map +1 -0
  66. package/dest/public/bytecode_errors.js +7 -0
  67. package/dest/public/enqueued_call_side_effect_trace.d.ts +10 -4
  68. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
  69. package/dest/public/enqueued_call_side_effect_trace.js +63 -13
  70. package/dest/public/execution.d.ts +2 -2
  71. package/dest/public/execution.d.ts.map +1 -1
  72. package/dest/public/execution.js +1 -1
  73. package/dest/public/executor_metrics.d.ts +2 -0
  74. package/dest/public/executor_metrics.d.ts.map +1 -1
  75. package/dest/public/executor_metrics.js +11 -1
  76. package/dest/public/fee_payment.d.ts.map +1 -1
  77. package/dest/public/fee_payment.js +4 -3
  78. package/dest/public/fixtures/index.d.ts +17 -11
  79. package/dest/public/fixtures/index.d.ts.map +1 -1
  80. package/dest/public/fixtures/index.js +103 -35
  81. package/dest/public/public_db_sources.d.ts.map +1 -1
  82. package/dest/public/public_db_sources.js +7 -6
  83. package/dest/public/public_processor.d.ts +15 -7
  84. package/dest/public/public_processor.d.ts.map +1 -1
  85. package/dest/public/public_processor.js +119 -75
  86. package/dest/public/public_processor_metrics.d.ts +10 -2
  87. package/dest/public/public_processor_metrics.d.ts.map +1 -1
  88. package/dest/public/public_processor_metrics.js +49 -2
  89. package/dest/public/public_tx_context.d.ts +5 -0
  90. package/dest/public/public_tx_context.d.ts.map +1 -1
  91. package/dest/public/public_tx_context.js +40 -20
  92. package/dest/public/public_tx_simulator.d.ts +2 -1
  93. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  94. package/dest/public/public_tx_simulator.js +35 -6
  95. package/dest/public/side_effect_errors.js +2 -2
  96. package/dest/public/side_effect_trace_interface.d.ts +2 -1
  97. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  98. package/dest/public/transitional_adapters.d.ts.map +1 -1
  99. package/dest/public/transitional_adapters.js +2 -35
  100. package/dest/public/unique_class_ids.d.ts +37 -0
  101. package/dest/public/unique_class_ids.d.ts.map +1 -0
  102. package/dest/public/unique_class_ids.js +66 -0
  103. package/package.json +12 -12
  104. package/src/acvm/oracle/oracle.ts +2 -2
  105. package/src/acvm/oracle/typed_oracle.ts +2 -2
  106. package/src/avm/avm_memory_types.ts +56 -38
  107. package/src/avm/avm_simulator.ts +48 -20
  108. package/src/avm/avm_tree.ts +35 -92
  109. package/src/avm/errors.ts +13 -2
  110. package/src/avm/fixtures/index.ts +4 -2
  111. package/src/avm/journal/journal.ts +39 -29
  112. package/src/avm/journal/nullifiers.ts +0 -11
  113. package/src/avm/journal/public_storage.ts +2 -21
  114. package/src/avm/opcodes/addressing_mode.ts +2 -2
  115. package/src/avm/opcodes/conversion.ts +21 -16
  116. package/src/avm/opcodes/ec_add.ts +4 -3
  117. package/src/avm/opcodes/external_calls.ts +1 -1
  118. package/src/avm/opcodes/hashing.ts +6 -4
  119. package/src/avm/opcodes/misc.ts +4 -3
  120. package/src/avm/opcodes/multi_scalar_mul.ts +10 -5
  121. package/src/avm/test_utils.ts +4 -0
  122. package/src/client/client_execution_context.ts +2 -0
  123. package/src/client/db_oracle.ts +8 -3
  124. package/src/client/index.ts +1 -0
  125. package/src/client/view_data_oracle.ts +6 -3
  126. package/src/providers/acvm_wasm.ts +1 -1
  127. package/src/providers/acvm_wasm_with_blobs.ts +25 -0
  128. package/src/providers/index.ts +1 -1
  129. package/src/public/bytecode_errors.ts +6 -0
  130. package/src/public/enqueued_call_side_effect_trace.ts +83 -19
  131. package/src/public/execution.ts +1 -2
  132. package/src/public/executor_metrics.ts +13 -0
  133. package/src/public/fee_payment.ts +3 -2
  134. package/src/public/fixtures/index.ts +152 -46
  135. package/src/public/public_db_sources.ts +6 -5
  136. package/src/public/public_processor.ts +171 -88
  137. package/src/public/public_processor_metrics.ts +64 -2
  138. package/src/public/public_tx_context.ts +57 -21
  139. package/src/public/public_tx_simulator.ts +34 -6
  140. package/src/public/side_effect_errors.ts +1 -1
  141. package/src/public/side_effect_trace_interface.ts +2 -1
  142. package/src/public/transitional_adapters.ts +0 -51
  143. package/src/public/unique_class_ids.ts +80 -0
@@ -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,29 +61,9 @@ 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
- /**
61
- * Create a new state manager with some preloaded pending siloed nullifiers
62
- */
63
- public static async newWithPendingSiloedNullifiers(
64
- worldStateDB: WorldStateDB,
65
- trace: PublicSideEffectTraceInterface,
66
- pendingSiloedNullifiers: Fr[],
67
- doMerkleOperations: boolean = false,
68
- ) {
69
- const parentNullifiers = NullifierManager.newWithPendingSiloedNullifiers(worldStateDB, pendingSiloedNullifiers);
70
- const ephemeralForest = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
71
- return new AvmPersistableStateManager(
72
- worldStateDB,
73
- trace,
74
- /*publicStorage=*/ new PublicStorage(worldStateDB),
75
- /*nullifiers=*/ parentNullifiers.fork(),
76
- doMerkleOperations,
77
- ephemeralForest,
78
- );
79
- }
80
-
81
67
  /**
82
68
  * Create a new state manager
83
69
  */
@@ -85,6 +71,7 @@ export class AvmPersistableStateManager {
85
71
  worldStateDB: WorldStateDB,
86
72
  trace: PublicSideEffectTraceInterface,
87
73
  doMerkleOperations: boolean = false,
74
+ txHash: TxHash,
88
75
  ) {
89
76
  const ephemeralForest = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
90
77
  return new AvmPersistableStateManager(
@@ -94,6 +81,7 @@ export class AvmPersistableStateManager {
94
81
  /*nullifiers=*/ new NullifierManager(worldStateDB),
95
82
  /*doMerkleOperations=*/ doMerkleOperations,
96
83
  ephemeralForest,
84
+ txHash,
97
85
  );
98
86
  }
99
87
 
@@ -108,6 +96,7 @@ export class AvmPersistableStateManager {
108
96
  this.nullifiers.fork(),
109
97
  this.doMerkleOperations,
110
98
  this.merkleTrees.fork(),
99
+ this.txHash,
111
100
  );
112
101
  }
113
102
 
@@ -290,20 +279,41 @@ export class AvmPersistableStateManager {
290
279
  }
291
280
 
292
281
  /**
293
- * Write a note hash, trace the write.
282
+ * Write a raw note hash, silo it and make it unique, then trace the write.
294
283
  * @param noteHash - the unsiloed note hash to write
295
284
  */
296
285
  public writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): void {
297
- this.log.debug(`noteHashes(${contractAddress}) += @${noteHash}.`);
286
+ const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
287
+
288
+ this.writeSiloedNoteHash(siloedNoteHash);
289
+ }
290
+
291
+ /**
292
+ * Write a note hash, make it unique, trace the write.
293
+ * @param noteHash - the non unique note hash to write
294
+ */
295
+ public writeSiloedNoteHash(noteHash: Fr): void {
296
+ const txHash = Fr.fromBuffer(this.txHash.toBuffer());
297
+ const nonce = computeNoteHashNonce(txHash, this.trace.getNoteHashCount());
298
+ const uniqueNoteHash = computeUniqueNoteHash(nonce, noteHash);
299
+
300
+ this.writeUniqueNoteHash(uniqueNoteHash);
301
+ }
302
+
303
+ /**
304
+ * Write a note hash, trace the write.
305
+ * @param noteHash - the siloed unique hash to write
306
+ */
307
+ public writeUniqueNoteHash(noteHash: Fr): void {
308
+ this.log.debug(`noteHashes += @${noteHash}.`);
298
309
 
299
310
  if (this.doMerkleOperations) {
300
311
  // Should write a helper for this
301
312
  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);
313
+ const insertionPath = this.merkleTrees.appendNoteHash(noteHash);
314
+ this.trace.traceNewNoteHash(noteHash, leafIndex, insertionPath);
305
315
  } else {
306
- this.trace.traceNewNoteHash(contractAddress, noteHash);
316
+ this.trace.traceNewNoteHash(noteHash);
307
317
  }
308
318
  }
309
319
 
@@ -17,17 +17,6 @@ export class NullifierManager {
17
17
  private readonly parent?: NullifierManager,
18
18
  ) {}
19
19
 
20
- /**
21
- * Create a new nullifiers manager with some preloaded pending siloed nullifiers
22
- */
23
- public static newWithPendingSiloedNullifiers(hostNullifiers: CommitmentsDB, pendingSiloedNullifiers?: Fr[]) {
24
- const cachedSiloedNullifiers = new Set<bigint>();
25
- if (pendingSiloedNullifiers !== undefined) {
26
- pendingSiloedNullifiers.forEach(nullifier => cachedSiloedNullifiers.add(nullifier.toBigInt()));
27
- }
28
- return new NullifierManager(hostNullifiers, cachedSiloedNullifiers);
29
- }
30
-
31
20
  /**
32
21
  * Create a new nullifiers manager forked from this one
33
22
  */
@@ -1,4 +1,4 @@
1
- import { AztecAddress } from '@aztec/circuits.js';
1
+ import { type AztecAddress } from '@aztec/circuits.js';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
3
 
4
4
  import type { PublicStateDB } from '../../index.js';
@@ -33,13 +33,6 @@ export class PublicStorage {
33
33
  return new PublicStorage(this.hostPublicStorage, this);
34
34
  }
35
35
 
36
- /**
37
- * Get the pending storage.
38
- */
39
- public getCache() {
40
- return this.cache;
41
- }
42
-
43
36
  /**
44
37
  * Read a storage value from this' cache or parent's (recursively).
45
38
  * DOES NOT CHECK HOST STORAGE!
@@ -108,17 +101,6 @@ export class PublicStorage {
108
101
  public acceptAndMerge(incomingPublicStorage: PublicStorage) {
109
102
  this.cache.acceptAndMerge(incomingPublicStorage.cache);
110
103
  }
111
-
112
- /**
113
- * Commits ALL staged writes to the host's state.
114
- */
115
- public async commitToDB() {
116
- for (const [contractAddress, cacheAtContract] of this.cache.cachePerContract) {
117
- for (const [slot, value] of cacheAtContract) {
118
- await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(contractAddress), new Fr(slot), value);
119
- }
120
- }
121
- }
122
104
  }
123
105
 
124
106
  /**
@@ -132,8 +114,7 @@ class PublicStorageCache {
132
114
  * One inner-map per contract storage address,
133
115
  * mapping storage slot to latest staged write value.
134
116
  */
135
- public cachePerContract: Map<bigint, Map<bigint, Fr>> = new Map();
136
- // FIXME: storage ^ should be private, but its value is used in commitToDB
117
+ private cachePerContract: Map<bigint, Map<bigint, Fr>> = new Map();
137
118
 
138
119
  /**
139
120
  * Read a staged value from storage, if it has been previously written to.
@@ -1,7 +1,7 @@
1
1
  import { strict as assert } from 'assert';
2
2
 
3
3
  import { TaggedMemory, type TaggedMemoryInterface } from '../avm_memory_types.js';
4
- import { AddressOutOfRangeError } from '../errors.js';
4
+ import { RelativeAddressOutOfRangeError } from '../errors.js';
5
5
 
6
6
  export enum AddressingMode {
7
7
  DIRECT = 0,
@@ -67,7 +67,7 @@ export class Addressing {
67
67
  const baseAddr = Number(mem.get(0).toBigInt());
68
68
  resolved[i] += baseAddr;
69
69
  if (resolved[i] >= TaggedMemory.MAX_MEMORY_SIZE) {
70
- throw new AddressOutOfRangeError(baseAddr, offset);
70
+ throw new RelativeAddressOutOfRangeError(baseAddr, offset);
71
71
  }
72
72
  }
73
73
  if (mode & AddressingMode.INDIRECT) {
@@ -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
  }
@@ -84,10 +84,11 @@ export class EcAdd extends Instruction {
84
84
  dest = grumpkin.add(p1, p2);
85
85
  }
86
86
 
87
- memory.set(dstOffset, new Field(dest.x));
88
- memory.set(dstOffset + 1, new Field(dest.y));
87
+ // Important to use setSlice() and not set() in the two following statements as
88
+ // this checks that the offsets lie within memory range.
89
+ memory.setSlice(dstOffset, [new Field(dest.x), new Field(dest.y)]);
89
90
  // Check representation of infinity for grumpkin
90
- memory.set(dstOffset + 2, new Uint1(dest.equals(Point.ZERO) ? 1 : 0));
91
+ memory.setSlice(dstOffset + 2, [new Uint1(dest.equals(Point.ZERO) ? 1 : 0)]);
91
92
 
92
93
  memory.assert({ reads: 6, writes: 3, addressing });
93
94
  }
@@ -39,10 +39,10 @@ abstract class ExternalCall extends Instruction {
39
39
  memory.checkTag(TypeTag.UINT32, argsSizeOffset);
40
40
 
41
41
  const calldataSize = memory.get(argsSizeOffset).toNumber();
42
+ const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
42
43
  memory.checkTagsRange(TypeTag.FIELD, argsOffset, calldataSize);
43
44
 
44
45
  const callAddress = memory.getAs<Field>(addrOffset);
45
- const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
46
46
  // If we are already in a static call, we propagate the environment.
47
47
  const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type;
48
48
 
@@ -30,9 +30,10 @@ export class Poseidon2 extends Instruction {
30
30
  const operands = [this.inputStateOffset, this.outputStateOffset];
31
31
  const addressing = Addressing.fromWire(this.indirect, operands.length);
32
32
  const [inputOffset, outputOffset] = addressing.resolve(operands, memory);
33
- memory.checkTagsRange(TypeTag.FIELD, inputOffset, Poseidon2.stateSize);
34
33
 
35
34
  const inputState = memory.getSlice(inputOffset, Poseidon2.stateSize);
35
+ memory.checkTagsRange(TypeTag.FIELD, inputOffset, Poseidon2.stateSize);
36
+
36
37
  const outputState = poseidon2Permutation(inputState);
37
38
  memory.setSlice(
38
39
  outputOffset,
@@ -68,9 +69,9 @@ export class KeccakF1600 extends Instruction {
68
69
  const [dstOffset, inputOffset] = addressing.resolve(operands, memory);
69
70
  context.machineState.consumeGas(this.gasCost());
70
71
 
72
+ const stateData = memory.getSlice(inputOffset, inputSize).map(word => word.toBigInt());
71
73
  memory.checkTagsRange(TypeTag.UINT64, inputOffset, inputSize);
72
74
 
73
- const stateData = memory.getSlice(inputOffset, inputSize).map(word => word.toBigInt());
74
75
  const updatedState = keccakf1600(stateData);
75
76
 
76
77
  const res = updatedState.map(word => new Uint64(word));
@@ -113,11 +114,12 @@ export class Sha256Compression extends Instruction {
113
114
 
114
115
  // Note: size of output is same as size of state
115
116
  context.machineState.consumeGas(this.gasCost());
117
+ const inputs = Uint32Array.from(memory.getSlice(inputsOffset, INPUTS_SIZE).map(word => word.toNumber()));
118
+ const state = Uint32Array.from(memory.getSlice(stateOffset, STATE_SIZE).map(word => word.toNumber()));
119
+
116
120
  memory.checkTagsRange(TypeTag.UINT32, inputsOffset, INPUTS_SIZE);
117
121
  memory.checkTagsRange(TypeTag.UINT32, stateOffset, STATE_SIZE);
118
122
 
119
- const state = Uint32Array.from(memory.getSlice(stateOffset, STATE_SIZE).map(word => word.toNumber()));
120
- const inputs = Uint32Array.from(memory.getSlice(inputsOffset, INPUTS_SIZE).map(word => word.toNumber()));
121
123
  const output = sha256Compression(state, inputs);
122
124
 
123
125
  // Conversion required from Uint32Array to Uint32[] (can't map directly, need `...`)
@@ -39,14 +39,15 @@ export class DebugLog extends Instruction {
39
39
 
40
40
  memory.checkTag(TypeTag.UINT32, fieldsSizeOffset);
41
41
  const fieldsSize = memory.get(fieldsSizeOffset).toNumber();
42
+
43
+ const rawMessage = memory.getSlice(messageOffset, this.messageSize);
44
+ const fields = memory.getSlice(fieldsOffset, fieldsSize);
45
+
42
46
  memory.checkTagsRange(TypeTag.UINT8, messageOffset, this.messageSize);
43
47
  memory.checkTagsRange(TypeTag.FIELD, fieldsOffset, fieldsSize);
44
48
 
45
49
  context.machineState.consumeGas(this.gasCost(this.messageSize + fieldsSize));
46
50
 
47
- const rawMessage = memory.getSlice(messageOffset, this.messageSize);
48
- const fields = memory.getSlice(fieldsOffset, fieldsSize);
49
-
50
51
  // Interpret str<N> = [u8; N] to string.
51
52
  const messageAsStr = rawMessage.map(field => String.fromCharCode(field.toNumber())).join('');
52
53
  const formattedStr = applyStringFormatting(
@@ -46,6 +46,12 @@ export class MultiScalarMul extends Instruction {
46
46
  if (pointsReadLength % 3 !== 0) {
47
47
  throw new InstructionExecutionError(`Points vector offset should be a multiple of 3, was ${pointsReadLength}`);
48
48
  }
49
+
50
+ // Get the unrolled (x, y, inf) representing the points
51
+ // Important to perform this before tag validation, as getSlice() first checks
52
+ // that the slice is not out of memory range. This needs to be aligned with circuit.
53
+ const pointsVector = memory.getSlice(pointsOffset, pointsReadLength);
54
+
49
55
  // Divide by 3 since each point is represented as a triplet to get the number of points
50
56
  const numPoints = pointsReadLength / 3;
51
57
  // The tag for each triplet will be (Field, Field, Uint8)
@@ -56,8 +62,6 @@ export class MultiScalarMul extends Instruction {
56
62
  // Check Uint1 (inf flag)
57
63
  memory.checkTag(TypeTag.UINT1, offset + 2);
58
64
  }
59
- // Get the unrolled (x, y, inf) representing the points
60
- const pointsVector = memory.getSlice(pointsOffset, pointsReadLength);
61
65
 
62
66
  // The size of the scalars vector is twice the NUMBER of points because of the scalar limb decomposition
63
67
  const scalarReadLength = numPoints * 2;
@@ -106,10 +110,11 @@ export class MultiScalarMul extends Instruction {
106
110
  }
107
111
  }, grumpkin.mul(firstBaseScalarPair[0], firstBaseScalarPair[1]));
108
112
 
109
- memory.set(outputOffset, new Field(outputPoint.x));
110
- memory.set(outputOffset + 1, new Field(outputPoint.y));
113
+ // Important to use setSlice() and not set() in the two following statements as
114
+ // this checks that the offsets lie within memory range.
115
+ memory.setSlice(outputOffset, [new Field(outputPoint.x), new Field(outputPoint.y)]);
111
116
  // Check representation of infinity for grumpkin
112
- memory.set(outputOffset + 2, new Uint1(outputPoint.equals(Point.ZERO) ? 1 : 0));
117
+ memory.setSlice(outputOffset + 2, [new Uint1(outputPoint.equals(Point.ZERO) ? 1 : 0)]);
113
118
 
114
119
  memory.assert({
115
120
  reads: 1 + pointsReadLength + scalarReadLength /* points and scalars */,
@@ -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';
@@ -0,0 +1,6 @@
1
+ export class ContractClassBytecodeError extends Error {
2
+ constructor(contractAddress: string) {
3
+ super(`Failed to get bytecode for contract at address ${contractAddress}`);
4
+ this.name = 'ContractClassBytecodeError';
5
+ }
6
+ }