@aztec/simulator 0.47.1 → 0.49.2

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 (103) hide show
  1. package/dest/acvm/acvm.d.ts +2 -2
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/acvm.js +12 -7
  4. package/dest/acvm/oracle/oracle.d.ts +3 -3
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +8 -9
  7. package/dest/acvm/oracle/typed_oracle.d.ts +5 -5
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +6 -6
  10. package/dest/avm/avm_gas.d.ts +1 -0
  11. package/dest/avm/avm_gas.d.ts.map +1 -1
  12. package/dest/avm/avm_gas.js +142 -79
  13. package/dest/avm/fixtures/index.d.ts.map +1 -1
  14. package/dest/avm/fixtures/index.js +2 -2
  15. package/dest/avm/opcodes/accrued_substate.js +2 -2
  16. package/dest/avm/opcodes/commitment.js +4 -4
  17. package/dest/avm/opcodes/conversion.js +2 -2
  18. package/dest/avm/opcodes/external_calls.js +4 -4
  19. package/dest/avm/opcodes/instruction.d.ts +2 -1
  20. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  21. package/dest/avm/opcodes/instruction.js +8 -5
  22. package/dest/avm/opcodes/memory.js +2 -2
  23. package/dest/avm/opcodes/storage.js +3 -3
  24. package/dest/avm/serialization/instruction_serialization.js +2 -2
  25. package/dest/client/client_execution_context.d.ts +8 -8
  26. package/dest/client/client_execution_context.d.ts.map +1 -1
  27. package/dest/client/client_execution_context.js +22 -23
  28. package/dest/client/db_oracle.d.ts +4 -3
  29. package/dest/client/db_oracle.d.ts.map +1 -1
  30. package/dest/client/execution_note_cache.d.ts +17 -13
  31. package/dest/client/execution_note_cache.d.ts.map +1 -1
  32. package/dest/client/execution_note_cache.js +65 -26
  33. package/dest/client/execution_result.d.ts +3 -2
  34. package/dest/client/execution_result.d.ts.map +1 -1
  35. package/dest/client/execution_result.js +20 -9
  36. package/dest/client/private_execution.js +3 -3
  37. package/dest/client/simulator.d.ts +7 -6
  38. package/dest/client/simulator.d.ts.map +1 -1
  39. package/dest/client/simulator.js +14 -12
  40. package/dest/client/test_utils.d.ts +9 -0
  41. package/dest/client/test_utils.d.ts.map +1 -0
  42. package/dest/client/test_utils.js +21 -0
  43. package/dest/client/view_data_oracle.d.ts +2 -1
  44. package/dest/client/view_data_oracle.d.ts.map +1 -1
  45. package/dest/client/view_data_oracle.js +4 -3
  46. package/dest/index.d.ts +0 -1
  47. package/dest/index.d.ts.map +1 -1
  48. package/dest/index.js +1 -2
  49. package/dest/providers/acvm_native.js +2 -2
  50. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  51. package/dest/public/abstract_phase_manager.js +3 -3
  52. package/dest/public/executor.d.ts +4 -1
  53. package/dest/public/executor.d.ts.map +1 -1
  54. package/dest/public/executor.js +10 -2
  55. package/dest/public/executor_metrics.d.ts +10 -0
  56. package/dest/public/executor_metrics.d.ts.map +1 -0
  57. package/dest/public/executor_metrics.js +32 -0
  58. package/dest/public/fee_payment.d.ts +2 -2
  59. package/dest/public/fee_payment.d.ts.map +1 -1
  60. package/dest/public/fee_payment.js +9 -10
  61. package/dest/public/hints_builder.d.ts.map +1 -1
  62. package/dest/public/hints_builder.js +1 -1
  63. package/dest/public/public_processor.d.ts +6 -5
  64. package/dest/public/public_processor.d.ts.map +1 -1
  65. package/dest/public/public_processor.js +38 -18
  66. package/dest/public/public_processor_metrics.d.ts +19 -0
  67. package/dest/public/public_processor_metrics.d.ts.map +1 -0
  68. package/dest/public/public_processor_metrics.js +59 -0
  69. package/package.json +9 -9
  70. package/src/acvm/acvm.ts +14 -5
  71. package/src/acvm/oracle/oracle.ts +8 -23
  72. package/src/acvm/oracle/typed_oracle.ts +8 -21
  73. package/src/avm/avm_gas.ts +145 -79
  74. package/src/avm/fixtures/index.ts +1 -0
  75. package/src/avm/opcodes/accrued_substate.ts +1 -1
  76. package/src/avm/opcodes/commitment.ts +3 -3
  77. package/src/avm/opcodes/conversion.ts +1 -1
  78. package/src/avm/opcodes/external_calls.ts +3 -3
  79. package/src/avm/opcodes/instruction.ts +7 -4
  80. package/src/avm/opcodes/memory.ts +1 -1
  81. package/src/avm/opcodes/storage.ts +2 -2
  82. package/src/avm/serialization/instruction_serialization.ts +1 -1
  83. package/src/client/client_execution_context.ts +23 -20
  84. package/src/client/db_oracle.ts +9 -3
  85. package/src/client/execution_note_cache.ts +76 -25
  86. package/src/client/execution_result.ts +29 -9
  87. package/src/client/private_execution.ts +2 -2
  88. package/src/client/simulator.ts +18 -14
  89. package/src/client/test_utils.ts +30 -0
  90. package/src/client/view_data_oracle.ts +2 -1
  91. package/src/index.ts +0 -1
  92. package/src/providers/acvm_native.ts +1 -1
  93. package/src/public/abstract_phase_manager.ts +1 -2
  94. package/src/public/executor.ts +14 -1
  95. package/src/public/executor_metrics.ts +48 -0
  96. package/src/public/fee_payment.ts +8 -10
  97. package/src/public/hints_builder.ts +2 -2
  98. package/src/public/public_processor.ts +52 -20
  99. package/src/public/public_processor_metrics.ts +92 -0
  100. package/dest/utils.d.ts +0 -12
  101. package/dest/utils.d.ts.map +0 -1
  102. package/dest/utils.js +0 -11
  103. package/src/utils.ts +0 -18
@@ -1,12 +1,13 @@
1
- import { siloNullifier } from '@aztec/circuits.js/hash';
1
+ import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
2
2
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
3
- import { Fr } from '@aztec/foundation/fields';
3
+ import { type Fr } from '@aztec/foundation/fields';
4
4
 
5
5
  import { type NoteData } from '../acvm/index.js';
6
6
 
7
- export interface PendingNote {
7
+ interface PendingNote {
8
8
  note: NoteData;
9
9
  counter: number;
10
+ noteHashForConsumption: Fr;
10
11
  }
11
12
 
12
13
  /**
@@ -15,9 +16,13 @@ export interface PendingNote {
15
16
  export class ExecutionNoteCache {
16
17
  /**
17
18
  * New notes created in this transaction.
19
+ * They are pushed to this array in the same order as they are emitted.
20
+ */
21
+ private notes: PendingNote[] = [];
22
+ /**
18
23
  * This mapping maps from a contract address to the notes in the contract.
19
24
  */
20
- private newNotes: Map<bigint, PendingNote[]> = new Map();
25
+ private noteMap: Map<bigint, PendingNote[]> = new Map();
21
26
 
22
27
  /**
23
28
  * The list of nullifiers created in this transaction.
@@ -25,43 +30,81 @@ export class ExecutionNoteCache {
25
30
  * The note which is nullified might be new or not (i.e., was generated in a previous transaction).
26
31
  * Note that their value (bigint representation) is used because Frs cannot be looked up in Sets.
27
32
  */
28
- private nullifiers: Map<bigint, Set<bigint>> = new Map();
33
+ private nullifierMap: Map<bigint, Set<bigint>> = new Map();
34
+
35
+ private minRevertibleSideEffectCounter = 0;
36
+
37
+ constructor(private readonly txHash: Fr) {}
38
+
39
+ public setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter: number) {
40
+ if (this.minRevertibleSideEffectCounter && this.minRevertibleSideEffectCounter !== minRevertibleSideEffectCounter) {
41
+ throw new Error(
42
+ `Cannot override minRevertibleSideEffectCounter. Current value: ${minRevertibleSideEffectCounter}. Previous value: ${this.minRevertibleSideEffectCounter}`,
43
+ );
44
+ }
45
+
46
+ this.minRevertibleSideEffectCounter = minRevertibleSideEffectCounter;
47
+
48
+ // The existing pending notes are all non-revertible.
49
+ // They cannot be squashed by nullifiers emitted after minRevertibleSideEffectCounter is set.
50
+ // Their indexes in the tx are known at this point and won't change. So we can assign a nonce to each one of them.
51
+ // The nonces will be used to create the "complete" nullifier.
52
+ const updatedNotes = this.notes.map(({ note, counter }, i) => {
53
+ const nonce = computeNoteHashNonce(this.txHash, i);
54
+ const uniqueNoteHash = computeUniqueNoteHash(nonce, note.noteHash);
55
+ return {
56
+ counter,
57
+ note: { ...note, nonce },
58
+ noteHashForConsumption: siloNoteHash(note.contractAddress, uniqueNoteHash),
59
+ };
60
+ });
61
+ // Rebuild the data.
62
+ this.notes = [];
63
+ this.noteMap = new Map();
64
+ updatedNotes.forEach(n => this.#addNote(n));
65
+ }
29
66
 
30
67
  /**
31
68
  * Add a new note to cache.
32
69
  * @param note - New note created during execution.
33
70
  */
34
71
  public addNewNote(note: NoteData, counter: number) {
35
- const notes = this.newNotes.get(note.contractAddress.toBigInt()) ?? [];
36
- notes.push({ note, counter });
37
- this.newNotes.set(note.contractAddress.toBigInt(), notes);
72
+ const previousNote = this.notes[this.notes.length - 1];
73
+ if (previousNote && previousNote.counter >= counter) {
74
+ throw new Error(
75
+ `Note hash counters must be strictly increasing. Current counter: ${counter}. Previous counter: ${previousNote.counter}.`,
76
+ );
77
+ }
78
+
79
+ this.#addNote({ note, counter, noteHashForConsumption: note.noteHash });
38
80
  }
39
81
 
40
82
  /**
41
83
  * Add a nullifier to cache. It could be for a db note or a new note created during execution.
42
84
  * @param contractAddress - Contract address of the note.
43
- * @param storageSlot - Storage slot of the note.
44
85
  * @param innerNullifier - Inner nullifier of the note.
45
- * @param innerNoteHash - Inner note hash of the note. If this value equals 0, it means the
46
- * note being nullified is from a previous transaction (and thus not a new note).
86
+ * @param noteHash - A hash of the note. If this value equals 0, it means the note being nullified is from a previous
87
+ * transaction (and thus not a new note).
47
88
  */
48
- public nullifyNote(contractAddress: AztecAddress, innerNullifier: Fr, innerNoteHash: Fr) {
89
+ public nullifyNote(contractAddress: AztecAddress, innerNullifier: Fr, noteHash: Fr) {
49
90
  const siloedNullifier = siloNullifier(contractAddress, innerNullifier);
50
91
  const nullifiers = this.getNullifiers(contractAddress);
51
92
  nullifiers.add(siloedNullifier.value);
52
- this.nullifiers.set(contractAddress.toBigInt(), nullifiers);
93
+ this.nullifierMap.set(contractAddress.toBigInt(), nullifiers);
53
94
 
54
95
  let nullifiedNoteHashCounter: number | undefined = undefined;
55
- // Find and remove the matching new note and log(s) if the emitted innerNoteHash is not empty.
56
- if (!innerNoteHash.equals(Fr.ZERO)) {
57
- const notes = this.newNotes.get(contractAddress.toBigInt()) ?? [];
58
- const noteIndexToRemove = notes.findIndex(n => n.note.innerNoteHash.equals(innerNoteHash));
96
+ // Find and remove the matching new note and log(s) if the emitted noteHash is not empty.
97
+ if (!noteHash.isEmpty()) {
98
+ const notesInContract = this.noteMap.get(contractAddress.toBigInt()) ?? [];
99
+ const noteIndexToRemove = notesInContract.findIndex(n => n.noteHashForConsumption.equals(noteHash));
59
100
  if (noteIndexToRemove === -1) {
60
101
  throw new Error('Attempt to remove a pending note that does not exist.');
61
102
  }
62
- const note = notes.splice(noteIndexToRemove, 1)[0];
103
+
104
+ const note = notesInContract.splice(noteIndexToRemove, 1)[0];
63
105
  nullifiedNoteHashCounter = note.counter;
64
- this.newNotes.set(contractAddress.toBigInt(), notes);
106
+ this.noteMap.set(contractAddress.toBigInt(), notesInContract);
107
+ this.notes = this.notes.filter(n => n.counter !== note.counter);
65
108
  }
66
109
  return nullifiedNoteHashCounter;
67
110
  }
@@ -73,7 +116,7 @@ export class ExecutionNoteCache {
73
116
  * @param storageSlot - Storage slot of the notes.
74
117
  **/
75
118
  public getNotes(contractAddress: AztecAddress, storageSlot: Fr) {
76
- const notes = this.newNotes.get(contractAddress.toBigInt()) ?? [];
119
+ const notes = this.noteMap.get(contractAddress.toBigInt()) ?? [];
77
120
  return notes.filter(n => n.note.storageSlot.equals(storageSlot)).map(n => n.note);
78
121
  }
79
122
 
@@ -81,11 +124,11 @@ export class ExecutionNoteCache {
81
124
  * Check if a note exists in the newNotes array.
82
125
  * @param contractAddress - Contract address of the note.
83
126
  * @param storageSlot - Storage slot of the note.
84
- * @param innerNoteHash - Inner note hash of the note.
127
+ * @param noteHash - A hash of the note.
85
128
  **/
86
- public checkNoteExists(contractAddress: AztecAddress, innerNoteHash: Fr) {
87
- const notes = this.newNotes.get(contractAddress.toBigInt()) ?? [];
88
- return notes.some(n => n.note.innerNoteHash.equals(innerNoteHash));
129
+ public checkNoteExists(contractAddress: AztecAddress, noteHash: Fr) {
130
+ const notes = this.noteMap.get(contractAddress.toBigInt()) ?? [];
131
+ return notes.some(n => n.note.noteHash.equals(noteHash));
89
132
  }
90
133
 
91
134
  /**
@@ -93,6 +136,14 @@ export class ExecutionNoteCache {
93
136
  * @param contractAddress - Address of the contract.
94
137
  */
95
138
  public getNullifiers(contractAddress: AztecAddress): Set<bigint> {
96
- return this.nullifiers.get(contractAddress.toBigInt()) ?? new Set();
139
+ return this.nullifierMap.get(contractAddress.toBigInt()) ?? new Set();
140
+ }
141
+
142
+ #addNote(note: PendingNote) {
143
+ this.notes.push(note);
144
+
145
+ const notes = this.noteMap.get(note.note.contractAddress.toBigInt()) ?? [];
146
+ notes.push(note);
147
+ this.noteMap.set(note.note.contractAddress.toBigInt(), notes);
97
148
  }
98
149
  }
@@ -67,7 +67,7 @@ export interface ExecutionResult {
67
67
  /** The notes created in the executed function. */
68
68
  newNotes: NoteAndSlot[];
69
69
  /** Mapping of note hash counter to the counter of its nullifier. */
70
- nullifiedNoteHashCounters: Map<number, number>;
70
+ noteHashNullifierCounterMap: Map<number, number>;
71
71
  /** The raw return values of the executed function. */
72
72
  returnValues: Fr[];
73
73
  /** The nested executions. */
@@ -99,9 +99,12 @@ export function collectNoteHashLeafIndexMap(execResult: ExecutionResult, accum:
99
99
  return accum;
100
100
  }
101
101
 
102
- export function collectNullifiedNoteHashCounters(execResult: ExecutionResult, accum: Map<number, number> = new Map()) {
103
- execResult.nullifiedNoteHashCounters.forEach((value, key) => accum.set(key, value));
104
- execResult.nestedExecutions.forEach(nested => collectNullifiedNoteHashCounters(nested, accum));
102
+ export function collectNoteHashNullifierCounterMap(
103
+ execResult: ExecutionResult,
104
+ accum: Map<number, number> = new Map(),
105
+ ) {
106
+ execResult.noteHashNullifierCounterMap.forEach((value, key) => accum.set(key, value));
107
+ execResult.nestedExecutions.forEach(nested => collectNoteHashNullifierCounterMap(nested, accum));
105
108
  return accum;
106
109
  }
107
110
 
@@ -112,11 +115,20 @@ export function collectNullifiedNoteHashCounters(execResult: ExecutionResult, ac
112
115
  */
113
116
  function collectNoteEncryptedLogs(
114
117
  execResult: ExecutionResult,
115
- nullifiedNoteHashCounters: Map<number, number>,
118
+ noteHashNullifierCounterMap: Map<number, number>,
119
+ minRevertibleSideEffectCounter: number,
116
120
  ): CountedLog<EncryptedL2NoteLog>[] {
117
121
  return [
118
- execResult.noteEncryptedLogs.filter(noteLog => !nullifiedNoteHashCounters.has(noteLog.noteHashCounter)),
119
- ...execResult.nestedExecutions.flatMap(res => collectNoteEncryptedLogs(res, nullifiedNoteHashCounters)),
122
+ execResult.noteEncryptedLogs.filter(noteLog => {
123
+ const nullifierCounter = noteHashNullifierCounterMap.get(noteLog.noteHashCounter);
124
+ return (
125
+ nullifierCounter === undefined ||
126
+ (noteLog.noteHashCounter < minRevertibleSideEffectCounter && nullifierCounter >= minRevertibleSideEffectCounter)
127
+ );
128
+ }),
129
+ ...execResult.nestedExecutions.flatMap(res =>
130
+ collectNoteEncryptedLogs(res, noteHashNullifierCounterMap, minRevertibleSideEffectCounter),
131
+ ),
120
132
  ].flat();
121
133
  }
122
134
 
@@ -126,8 +138,9 @@ function collectNoteEncryptedLogs(
126
138
  * @returns All encrypted logs.
127
139
  */
128
140
  export function collectSortedNoteEncryptedLogs(execResult: ExecutionResult): EncryptedNoteFunctionL2Logs {
129
- const nullifiedNoteHashCounters = collectNullifiedNoteHashCounters(execResult);
130
- const allLogs = collectNoteEncryptedLogs(execResult, nullifiedNoteHashCounters);
141
+ const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(execResult);
142
+ const minRevertibleSideEffectCounter = getFinalMinRevertibleSideEffectCounter(execResult);
143
+ const allLogs = collectNoteEncryptedLogs(execResult, noteHashNullifierCounterMap, minRevertibleSideEffectCounter);
131
144
  const sortedLogs = sortByCounter(allLogs);
132
145
  return new EncryptedNoteFunctionL2Logs(sortedLogs.map(l => l.log));
133
146
  }
@@ -206,3 +219,10 @@ export function collectPublicTeardownFunctionCall(execResult: ExecutionResult):
206
219
 
207
220
  return PublicExecutionRequest.empty();
208
221
  }
222
+
223
+ export function getFinalMinRevertibleSideEffectCounter(execResult: ExecutionResult): number {
224
+ return execResult.nestedExecutions.reduce((counter, exec) => {
225
+ const nestedCounter = getFinalMinRevertibleSideEffectCounter(exec);
226
+ return nestedCounter ? nestedCounter : counter;
227
+ }, execResult.callStackItem.publicInputs.minRevertibleSideEffectCounter.toNumber());
228
+ }
@@ -68,7 +68,7 @@ export async function executePrivateFunction(
68
68
 
69
69
  const noteHashLeafIndexMap = context.getNoteHashLeafIndexMap();
70
70
  const newNotes = context.getNewNotes();
71
- const nullifiedNoteHashCounters = context.getNullifiedNoteHashCounters();
71
+ const noteHashNullifierCounterMap = context.getNoteHashNullifierCounterMap();
72
72
  const nestedExecutions = context.getNestedExecutions();
73
73
  const enqueuedPublicFunctionCalls = context.getEnqueuedPublicFunctionCalls();
74
74
  const publicTeardownFunctionCall = context.getPublicTeardownFunctionCall();
@@ -82,7 +82,7 @@ export async function executePrivateFunction(
82
82
  returnValues: rawReturnValues,
83
83
  noteHashLeafIndexMap,
84
84
  newNotes,
85
- nullifiedNoteHashCounters,
85
+ noteHashNullifierCounterMap,
86
86
  vk: Buffer.from(artifact.verificationKey!, 'hex'),
87
87
  nestedExecutions,
88
88
  enqueuedPublicFunctionCalls,
@@ -38,6 +38,7 @@ export class AcirSimulator {
38
38
  * @param entryPointArtifact - The artifact of the entry point function.
39
39
  * @param contractAddress - The address of the contract (should match request.origin)
40
40
  * @param msgSender - The address calling the function. This can be replaced to simulate a call from another contract or a specific account.
41
+ * @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
41
42
  * @returns The result of the execution.
42
43
  */
43
44
  public async run(
@@ -45,6 +46,7 @@ export class AcirSimulator {
45
46
  entryPointArtifact: FunctionArtifact,
46
47
  contractAddress: AztecAddress,
47
48
  msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE),
49
+ scopes?: AztecAddress[],
48
50
  ): Promise<ExecutionResult> {
49
51
  if (entryPointArtifact.functionType !== FunctionType.PRIVATE) {
50
52
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as private`);
@@ -68,6 +70,9 @@ export class AcirSimulator {
68
70
  false,
69
71
  entryPointArtifact.isStatic,
70
72
  );
73
+
74
+ const txHash = request.toTxRequest().hash();
75
+
71
76
  const context = new ClientExecutionContext(
72
77
  contractAddress,
73
78
  request.firstCallArgsHash,
@@ -76,10 +81,12 @@ export class AcirSimulator {
76
81
  header,
77
82
  request.authWitnesses,
78
83
  PackedValuesCache.create(request.argsOfCalls),
79
- new ExecutionNoteCache(),
84
+ new ExecutionNoteCache(txHash),
80
85
  this.db,
81
86
  this.node,
82
87
  startSideEffectCounter,
88
+ undefined,
89
+ scopes,
83
90
  );
84
91
 
85
92
  try {
@@ -100,18 +107,19 @@ export class AcirSimulator {
100
107
  * @param request - The transaction request.
101
108
  * @param entryPointArtifact - The artifact of the entry point function.
102
109
  * @param contractAddress - The address of the contract.
103
- * @param aztecNode - The AztecNode instance.
110
+ * @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
104
111
  */
105
112
  public async runUnconstrained(
106
113
  request: FunctionCall,
107
114
  entryPointArtifact: FunctionArtifact,
108
115
  contractAddress: AztecAddress,
116
+ scopes?: AztecAddress[],
109
117
  ) {
110
118
  if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) {
111
119
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as unconstrained`);
112
120
  }
113
121
 
114
- const context = new ViewDataOracle(contractAddress, [], this.db, this.node);
122
+ const context = new ViewDataOracle(contractAddress, [], this.db, this.node, undefined, scopes);
115
123
 
116
124
  try {
117
125
  return await executeUnconstrainedFunction(
@@ -188,14 +196,15 @@ export class AcirSimulator {
188
196
  returnTypes: artifact.returnTypes,
189
197
  };
190
198
 
191
- const [innerNoteHash, uniqueNoteHash, siloedNoteHash, innerNullifier] = (await this.runUnconstrained(
199
+ const [noteHash, uniqueNoteHash, siloedNoteHash, innerNullifier] = (await this.runUnconstrained(
192
200
  execRequest,
193
201
  artifact,
194
202
  contractAddress,
203
+ // We can omit scopes here, because "compute_note_hash_and_optionally_a_nullifier" does not need access to any notes.
195
204
  )) as bigint[];
196
205
 
197
206
  return {
198
- innerNoteHash: new Fr(innerNoteHash),
207
+ noteHash: new Fr(noteHash),
199
208
  uniqueNoteHash: new Fr(uniqueNoteHash),
200
209
  siloedNoteHash: new Fr(siloedNoteHash),
201
210
  innerNullifier: new Fr(innerNullifier),
@@ -203,20 +212,15 @@ export class AcirSimulator {
203
212
  }
204
213
 
205
214
  /**
206
- * Computes the inner note hash of a note, which contains storage slot and the custom note hash.
215
+ * Computes a hash of the note.
207
216
  * @param contractAddress - The address of the contract.
208
217
  * @param storageSlot - The storage slot.
209
218
  * @param noteTypeId - The note type identifier.
210
219
  * @param note - The note.
211
220
  * @returns The note hash.
212
221
  */
213
- public async computeInnerNoteHash(
214
- contractAddress: AztecAddress,
215
- storageSlot: Fr,
216
- noteTypeId: NoteSelector,
217
- note: Note,
218
- ) {
219
- const { innerNoteHash } = await this.computeNoteHashAndOptionallyANullifier(
222
+ public async computeNoteHash(contractAddress: AztecAddress, storageSlot: Fr, noteTypeId: NoteSelector, note: Note) {
223
+ const { noteHash } = await this.computeNoteHashAndOptionallyANullifier(
220
224
  contractAddress,
221
225
  Fr.ZERO,
222
226
  storageSlot,
@@ -224,6 +228,6 @@ export class AcirSimulator {
224
228
  false,
225
229
  note,
226
230
  );
227
- return innerNoteHash;
231
+ return noteHash;
228
232
  }
229
233
  }
@@ -0,0 +1,30 @@
1
+ import { Fq, Fr, GeneratorIndex, Point } from '@aztec/circuits.js';
2
+ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
3
+ import { pedersenCommit } from '@aztec/foundation/crypto';
4
+
5
+ // Copied over from `noir-projects/aztec-nr/aztec/src/generators.nr`
6
+ const G_SLOT = new Point(
7
+ new Fr(0x041223147b680850dc82e8a55a952d4df20256fe0593d949a9541ca00f0abf15n),
8
+ new Fr(0x0a8c72e60d0e60f5d804549d48f3044d06140b98ed717a9b532af630c1530791n),
9
+ false,
10
+ );
11
+
12
+ /**
13
+ * Computes a note hiding point as is done by the default implementation injected by macros.
14
+ * @param storageSlot - The slot to which the note was inserted.
15
+ * @param noteContent - The note content (e.g. note.items).
16
+ * @returns A note hash.
17
+ */
18
+ export function computeNoteHash(storageSlot: Fr, noteContent: Fr[]): Fr {
19
+ // TODO(#7771): update this to do only 1 MSM call
20
+ const c = pedersenCommit(
21
+ noteContent.map(f => f.toBuffer()),
22
+ GeneratorIndex.NOTE_HIDING_POINT,
23
+ );
24
+ const noteHidingPointBeforeSlotting = new Point(new Fr(c[0]), new Fr(c[1]), false);
25
+
26
+ const grumpkin = new Grumpkin();
27
+ const slotPoint = grumpkin.mul(G_SLOT, new Fq(storageSlot.toBigInt()));
28
+ const noteHidingPoint = grumpkin.add(noteHidingPointBeforeSlotting, slotPoint);
29
+ return noteHidingPoint.x;
30
+ }
@@ -30,6 +30,7 @@ export class ViewDataOracle extends TypedOracle {
30
30
  protected readonly db: DBOracle,
31
31
  protected readonly aztecNode: AztecNode,
32
32
  protected log = createDebugLogger('aztec:simulator:client_view_context'),
33
+ protected readonly scopes?: AztecAddress[],
33
34
  ) {
34
35
  super();
35
36
  }
@@ -219,7 +220,7 @@ export class ViewDataOracle extends TypedOracle {
219
220
  offset: number,
220
221
  status: NoteStatus,
221
222
  ): Promise<NoteData[]> {
222
- const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status);
223
+ const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status, this.scopes);
223
224
  return pickNotes<NoteData>(dbNotes, {
224
225
  selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
225
226
  selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
package/src/index.ts CHANGED
@@ -6,4 +6,3 @@ export * from './public/index.js';
6
6
  export * from './providers/index.js';
7
7
  export * from './mocks/index.js';
8
8
  export * from './stats/index.js';
9
- export * from './utils.js';
@@ -156,6 +156,6 @@ export class NativeACVMSimulator implements SimulationProvider {
156
156
  return result.witness;
157
157
  };
158
158
 
159
- return await runInDirectory(this.workingDirectory, operation);
159
+ return await runInDirectory(this.workingDirectory, operation, false);
160
160
  }
161
161
  }
@@ -14,7 +14,6 @@ import {
14
14
  import {
15
15
  type AvmExecutionHints,
16
16
  AztecAddress,
17
- ClientIvcProof,
18
17
  ContractStorageRead,
19
18
  ContractStorageUpdateRequest,
20
19
  Fr,
@@ -361,7 +360,7 @@ export abstract class AbstractPhaseManager {
361
360
  const previousKernel = this.getPreviousKernelData(previousOutput, previousCircuit);
362
361
 
363
362
  // We take a deep copy (clone) of these inputs to be passed to the prover
364
- const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, ClientIvcProof.empty(), callData);
363
+ const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData);
365
364
  switch (this.phase) {
366
365
  case PublicKernelType.SETUP:
367
366
  return [inputs.clone(), await this.publicKernel.publicKernelCircuitSetup(inputs), 'PublicKernelSetupArtifact'];
@@ -3,6 +3,7 @@ import { type AvmSimulationStats } from '@aztec/circuit-types/stats';
3
3
  import { Fr, Gas, type GlobalVariables, type Header, type Nullifier, type TxContext } from '@aztec/circuits.js';
4
4
  import { createDebugLogger } from '@aztec/foundation/log';
5
5
  import { Timer } from '@aztec/foundation/timer';
6
+ import { type TelemetryClient } from '@aztec/telemetry-client';
6
7
 
7
8
  import { AvmContext } from '../avm/avm_context.js';
8
9
  import { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js';
@@ -12,18 +13,24 @@ import { HostStorage } from '../avm/journal/host_storage.js';
12
13
  import { AvmPersistableStateManager } from '../avm/journal/index.js';
13
14
  import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from './db_interfaces.js';
14
15
  import { type PublicExecutionResult } from './execution.js';
16
+ import { ExecutorMetrics } from './executor_metrics.js';
15
17
  import { PublicSideEffectTrace } from './side_effect_trace.js';
16
18
 
17
19
  /**
18
20
  * Handles execution of public functions.
19
21
  */
20
22
  export class PublicExecutor {
23
+ metrics: ExecutorMetrics;
24
+
21
25
  constructor(
22
26
  private readonly publicStorageDB: PublicStateDB,
23
27
  private readonly contractsDb: PublicContractsDB,
24
28
  private readonly commitmentsDb: CommitmentsDB,
25
29
  private readonly header: Header,
26
- ) {}
30
+ client: TelemetryClient,
31
+ ) {
32
+ this.metrics = new ExecutorMetrics(client, 'PublicExecutor');
33
+ }
27
34
 
28
35
  static readonly log = createDebugLogger('aztec:simulator:public_executor');
29
36
 
@@ -102,6 +109,12 @@ export class PublicExecutor {
102
109
  fnName,
103
110
  );
104
111
 
112
+ if (publicExecutionResult.reverted) {
113
+ this.metrics.recordFunctionSimulationFailure();
114
+ } else {
115
+ this.metrics.recordFunctionSimulation(bytecode.length, timer.ms());
116
+ }
117
+
105
118
  return publicExecutionResult;
106
119
  }
107
120
  }
@@ -0,0 +1,48 @@
1
+ import {
2
+ Attributes,
3
+ type Histogram,
4
+ Metrics,
5
+ type TelemetryClient,
6
+ type UpDownCounter,
7
+ ValueType,
8
+ } from '@aztec/telemetry-client';
9
+
10
+ export class ExecutorMetrics {
11
+ private fnCount: UpDownCounter;
12
+ private fnDuration: Histogram;
13
+ private bytecodeSize: Histogram;
14
+
15
+ constructor(client: TelemetryClient, name = 'PublicExecutor') {
16
+ const meter = client.getMeter(name);
17
+
18
+ this.fnCount = meter.createUpDownCounter(Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT, {
19
+ description: 'Number of functions executed',
20
+ });
21
+
22
+ this.fnDuration = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_DURATION, {
23
+ description: 'How long it takes to execute a function',
24
+ unit: 'ms',
25
+ valueType: ValueType.INT,
26
+ });
27
+
28
+ this.bytecodeSize = meter.createHistogram(Metrics.PUBLIC_EXECUTION_SIMULATION_BYTECODE_SIZE, {
29
+ description: 'Size of the function bytecode',
30
+ unit: 'By',
31
+ valueType: ValueType.INT,
32
+ });
33
+ }
34
+
35
+ recordFunctionSimulation(bytecodeSize: number, durationMs: number) {
36
+ this.fnCount.add(1, {
37
+ [Attributes.OK]: true,
38
+ });
39
+ this.bytecodeSize.record(bytecodeSize);
40
+ this.fnDuration.record(Math.ceil(durationMs));
41
+ }
42
+
43
+ recordFunctionSimulationFailure() {
44
+ this.fnCount.add(1, {
45
+ [Attributes.OK]: false,
46
+ });
47
+ }
48
+ }
@@ -1,26 +1,24 @@
1
- import { GAS_TOKEN_ADDRESS } from '@aztec/circuits.js';
2
- import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
1
+ import { FEE_JUICE_ADDRESS } from '@aztec/circuits.js';
2
+ import { computePublicDataTreeLeafSlot, deriveStorageSlotInMap } from '@aztec/circuits.js/hash';
3
3
  import { AztecAddress } from '@aztec/foundation/aztec-address';
4
4
  import { Fr } from '@aztec/foundation/fields';
5
- import { GasTokenArtifact } from '@aztec/protocol-contracts/gas-token';
6
-
7
- import { computeSlotForMapping } from '../utils.js';
5
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
8
6
 
9
7
  /**
10
- * Computes the storage slot within the gas token contract for the balance of the fee payer.
8
+ * Computes the storage slot within the Fee Juice contract for the balance of the fee payer.
11
9
  */
12
10
  export function computeFeePayerBalanceStorageSlot(feePayer: AztecAddress) {
13
- return computeSlotForMapping(GasTokenArtifact.storageLayout.balances.slot, feePayer);
11
+ return deriveStorageSlotInMap(FeeJuiceArtifact.storageLayout.balances.slot, feePayer);
14
12
  }
15
13
 
16
14
  /**
17
- * Computes the leaf slot in the public data tree for the balance of the fee payer in the gas token.
15
+ * Computes the leaf slot in the public data tree for the balance of the fee payer in the Fee Juice.
18
16
  */
19
17
  export function computeFeePayerBalanceLeafSlot(feePayer: AztecAddress): Fr {
20
18
  if (feePayer.isZero()) {
21
19
  return Fr.ZERO;
22
20
  }
23
- const gasToken = AztecAddress.fromBigInt(GAS_TOKEN_ADDRESS);
21
+ const feeJuice = AztecAddress.fromBigInt(FEE_JUICE_ADDRESS);
24
22
  const balanceSlot = computeFeePayerBalanceStorageSlot(feePayer);
25
- return computePublicDataTreeLeafSlot(gasToken, balanceSlot);
23
+ return computePublicDataTreeLeafSlot(feeJuice, balanceSlot);
26
24
  }
@@ -1,4 +1,4 @@
1
- import { MerkleTreeId } from '@aztec/circuit-types';
1
+ import { type IndexedTreeId, MerkleTreeId } from '@aztec/circuit-types';
2
2
  import {
3
3
  type Fr,
4
4
  type MAX_NULLIFIERS_PER_TX,
@@ -23,7 +23,7 @@ import {
23
23
  buildSiloedNullifierReadRequestHints,
24
24
  } from '@aztec/circuits.js';
25
25
  import { type Tuple } from '@aztec/foundation/serialize';
26
- import { type IndexedTreeId, type MerkleTreeOperations } from '@aztec/world-state';
26
+ import { type MerkleTreeOperations } from '@aztec/world-state';
27
27
 
28
28
  export class HintsBuilder {
29
29
  constructor(private db: MerkleTreeOperations) {}