@aztec/simulator 0.47.0 → 0.48.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 (113) hide show
  1. package/dest/acvm/acvm.d.ts +1 -1
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.d.ts +5 -5
  4. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  5. package/dest/acvm/oracle/oracle.js +13 -16
  6. package/dest/acvm/oracle/typed_oracle.d.ts +12 -9
  7. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  8. package/dest/acvm/oracle/typed_oracle.js +6 -6
  9. package/dest/acvm/serialize.d.ts +0 -11
  10. package/dest/acvm/serialize.d.ts.map +1 -1
  11. package/dest/acvm/serialize.js +1 -26
  12. package/dest/avm/avm_gas.d.ts.map +1 -1
  13. package/dest/avm/avm_gas.js +2 -1
  14. package/dest/avm/fixtures/index.d.ts.map +1 -1
  15. package/dest/avm/fixtures/index.js +2 -2
  16. package/dest/avm/opcodes/commitment.d.ts +16 -0
  17. package/dest/avm/opcodes/commitment.d.ts.map +1 -0
  18. package/dest/avm/opcodes/commitment.js +50 -0
  19. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  20. package/dest/avm/serialization/bytecode_serialization.js +3 -1
  21. package/dest/avm/serialization/instruction_serialization.d.ts +4 -3
  22. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  23. package/dest/avm/serialization/instruction_serialization.js +6 -5
  24. package/dest/client/client_execution_context.d.ts +20 -17
  25. package/dest/client/client_execution_context.d.ts.map +1 -1
  26. package/dest/client/client_execution_context.js +42 -45
  27. package/dest/client/db_oracle.d.ts +4 -3
  28. package/dest/client/db_oracle.d.ts.map +1 -1
  29. package/dest/client/execution_note_cache.d.ts +17 -13
  30. package/dest/client/execution_note_cache.d.ts.map +1 -1
  31. package/dest/client/execution_note_cache.js +65 -26
  32. package/dest/client/execution_result.d.ts +15 -8
  33. package/dest/client/execution_result.d.ts.map +1 -1
  34. package/dest/client/execution_result.js +40 -16
  35. package/dest/client/private_execution.js +3 -3
  36. package/dest/client/simulator.d.ts +7 -6
  37. package/dest/client/simulator.d.ts.map +1 -1
  38. package/dest/client/simulator.js +14 -12
  39. package/dest/client/test_utils.d.ts +9 -0
  40. package/dest/client/test_utils.d.ts.map +1 -0
  41. package/dest/client/test_utils.js +21 -0
  42. package/dest/client/view_data_oracle.d.ts +2 -1
  43. package/dest/client/view_data_oracle.d.ts.map +1 -1
  44. package/dest/client/view_data_oracle.js +4 -3
  45. package/dest/index.d.ts +0 -1
  46. package/dest/index.d.ts.map +1 -1
  47. package/dest/index.js +1 -2
  48. package/dest/mocks/fixtures.d.ts +5 -5
  49. package/dest/mocks/fixtures.d.ts.map +1 -1
  50. package/dest/mocks/fixtures.js +6 -9
  51. package/dest/public/abstract_phase_manager.d.ts +4 -5
  52. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  53. package/dest/public/abstract_phase_manager.js +17 -84
  54. package/dest/public/execution.d.ts +8 -10
  55. package/dest/public/execution.d.ts.map +1 -1
  56. package/dest/public/execution.js +10 -1
  57. package/dest/public/executor.d.ts +6 -2
  58. package/dest/public/executor.d.ts.map +1 -1
  59. package/dest/public/executor.js +12 -4
  60. package/dest/public/executor_metrics.d.ts +10 -0
  61. package/dest/public/executor_metrics.d.ts.map +1 -0
  62. package/dest/public/executor_metrics.js +32 -0
  63. package/dest/public/fee_payment.d.ts +2 -2
  64. package/dest/public/fee_payment.d.ts.map +1 -1
  65. package/dest/public/fee_payment.js +9 -10
  66. package/dest/public/hints_builder.d.ts.map +1 -1
  67. package/dest/public/hints_builder.js +1 -1
  68. package/dest/public/index.d.ts +1 -1
  69. package/dest/public/index.d.ts.map +1 -1
  70. package/dest/public/index.js +1 -1
  71. package/dest/public/public_processor.d.ts +3 -3
  72. package/dest/public/public_processor.d.ts.map +1 -1
  73. package/dest/public/public_processor.js +33 -14
  74. package/dest/public/public_processor_metrics.d.ts +19 -0
  75. package/dest/public/public_processor_metrics.d.ts.map +1 -0
  76. package/dest/public/public_processor_metrics.js +57 -0
  77. package/dest/public/side_effect_trace.d.ts +1 -0
  78. package/dest/public/side_effect_trace.d.ts.map +1 -1
  79. package/dest/public/side_effect_trace.js +9 -9
  80. package/package.json +9 -9
  81. package/src/acvm/acvm.ts +1 -1
  82. package/src/acvm/oracle/oracle.ts +13 -30
  83. package/src/acvm/oracle/typed_oracle.ts +12 -31
  84. package/src/acvm/serialize.ts +0 -29
  85. package/src/avm/avm_gas.ts +1 -0
  86. package/src/avm/fixtures/index.ts +1 -0
  87. package/src/avm/opcodes/commitment.ts +66 -0
  88. package/src/avm/serialization/bytecode_serialization.ts +2 -0
  89. package/src/avm/serialization/instruction_serialization.ts +2 -1
  90. package/src/client/client_execution_context.ts +51 -49
  91. package/src/client/db_oracle.ts +9 -3
  92. package/src/client/execution_note_cache.ts +76 -25
  93. package/src/client/execution_result.ts +54 -19
  94. package/src/client/private_execution.ts +2 -2
  95. package/src/client/simulator.ts +18 -14
  96. package/src/client/test_utils.ts +30 -0
  97. package/src/client/view_data_oracle.ts +2 -1
  98. package/src/index.ts +0 -1
  99. package/src/mocks/fixtures.ts +13 -11
  100. package/src/public/abstract_phase_manager.ts +23 -104
  101. package/src/public/execution.ts +30 -14
  102. package/src/public/executor.ts +18 -4
  103. package/src/public/executor_metrics.ts +48 -0
  104. package/src/public/fee_payment.ts +8 -10
  105. package/src/public/hints_builder.ts +2 -2
  106. package/src/public/index.ts +1 -1
  107. package/src/public/public_processor.ts +46 -15
  108. package/src/public/public_processor_metrics.ts +90 -0
  109. package/src/public/side_effect_trace.ts +13 -7
  110. package/dest/utils.d.ts +0 -12
  111. package/dest/utils.d.ts.map +0 -1
  112. package/dest/utils.js +0 -11
  113. 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
  }
@@ -4,10 +4,11 @@ import {
4
4
  type EncryptedL2NoteLog,
5
5
  EncryptedNoteFunctionL2Logs,
6
6
  type Note,
7
+ PublicExecutionRequest,
7
8
  UnencryptedFunctionL2Logs,
8
9
  type UnencryptedL2Log,
9
10
  } from '@aztec/circuit-types';
10
- import { type IsEmpty, type PrivateCallStackItem, PublicCallRequest, sortByCounter } from '@aztec/circuits.js';
11
+ import { type IsEmpty, type PrivateCallStackItem, sortByCounter } from '@aztec/circuits.js';
11
12
  import { type NoteSelector } from '@aztec/foundation/abi';
12
13
  import { type Fr } from '@aztec/foundation/fields';
13
14
 
@@ -38,6 +39,15 @@ export class CountedNoteLog extends CountedLog<EncryptedL2NoteLog> {
38
39
  super(log, counter);
39
40
  }
40
41
  }
42
+
43
+ export class CountedPublicExecutionRequest {
44
+ constructor(public request: PublicExecutionRequest, public counter: number) {}
45
+
46
+ isEmpty(): boolean {
47
+ return this.request.isEmpty() && !this.counter;
48
+ }
49
+ }
50
+
41
51
  /**
42
52
  * The result of executing a private function.
43
53
  */
@@ -57,15 +67,15 @@ export interface ExecutionResult {
57
67
  /** The notes created in the executed function. */
58
68
  newNotes: NoteAndSlot[];
59
69
  /** Mapping of note hash counter to the counter of its nullifier. */
60
- nullifiedNoteHashCounters: Map<number, number>;
70
+ noteHashNullifierCounterMap: Map<number, number>;
61
71
  /** The raw return values of the executed function. */
62
72
  returnValues: Fr[];
63
73
  /** The nested executions. */
64
74
  nestedExecutions: this[];
65
75
  /** Enqueued public function execution requests to be picked up by the sequencer. */
66
- enqueuedPublicFunctionCalls: PublicCallRequest[];
76
+ enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[];
67
77
  /** Public function execution requested for teardown */
68
- publicTeardownFunctionCall: PublicCallRequest;
78
+ publicTeardownFunctionCall: PublicExecutionRequest;
69
79
  /**
70
80
  * Encrypted note logs emitted during execution of this function call.
71
81
  * Note: These are preimages to `noteEncryptedLogsHashes`.
@@ -89,9 +99,12 @@ export function collectNoteHashLeafIndexMap(execResult: ExecutionResult, accum:
89
99
  return accum;
90
100
  }
91
101
 
92
- export function collectNullifiedNoteHashCounters(execResult: ExecutionResult, accum: Map<number, number> = new Map()) {
93
- execResult.nullifiedNoteHashCounters.forEach((value, key) => accum.set(key, value));
94
- 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));
95
108
  return accum;
96
109
  }
97
110
 
@@ -102,11 +115,20 @@ export function collectNullifiedNoteHashCounters(execResult: ExecutionResult, ac
102
115
  */
103
116
  function collectNoteEncryptedLogs(
104
117
  execResult: ExecutionResult,
105
- nullifiedNoteHashCounters: Map<number, number>,
118
+ noteHashNullifierCounterMap: Map<number, number>,
119
+ minRevertibleSideEffectCounter: number,
106
120
  ): CountedLog<EncryptedL2NoteLog>[] {
107
121
  return [
108
- execResult.noteEncryptedLogs.filter(noteLog => !nullifiedNoteHashCounters.has(noteLog.noteHashCounter)),
109
- ...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
+ ),
110
132
  ].flat();
111
133
  }
112
134
 
@@ -116,8 +138,9 @@ function collectNoteEncryptedLogs(
116
138
  * @returns All encrypted logs.
117
139
  */
118
140
  export function collectSortedNoteEncryptedLogs(execResult: ExecutionResult): EncryptedNoteFunctionL2Logs {
119
- const nullifiedNoteHashCounters = collectNullifiedNoteHashCounters(execResult);
120
- const allLogs = collectNoteEncryptedLogs(execResult, nullifiedNoteHashCounters);
141
+ const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(execResult);
142
+ const minRevertibleSideEffectCounter = getFinalMinRevertibleSideEffectCounter(execResult);
143
+ const allLogs = collectNoteEncryptedLogs(execResult, noteHashNullifierCounterMap, minRevertibleSideEffectCounter);
121
144
  const sortedLogs = sortByCounter(allLogs);
122
145
  return new EncryptedNoteFunctionL2Logs(sortedLogs.map(l => l.log));
123
146
  }
@@ -161,21 +184,26 @@ export function collectSortedUnencryptedLogs(execResult: ExecutionResult): Unenc
161
184
  return new UnencryptedFunctionL2Logs(sortedLogs.map(l => l.log));
162
185
  }
163
186
 
187
+ function collectEnqueuedCountedPublicExecutionRequests(execResult: ExecutionResult): CountedPublicExecutionRequest[] {
188
+ return [
189
+ ...execResult.enqueuedPublicFunctionCalls,
190
+ ...execResult.nestedExecutions.flatMap(collectEnqueuedCountedPublicExecutionRequests),
191
+ ];
192
+ }
193
+
164
194
  /**
165
195
  * Collect all enqueued public function calls across all nested executions.
166
196
  * @param execResult - The topmost execution result.
167
197
  * @returns All enqueued public function calls.
168
198
  */
169
- export function collectEnqueuedPublicFunctionCalls(execResult: ExecutionResult): PublicCallRequest[] {
199
+ export function collectEnqueuedPublicFunctionCalls(execResult: ExecutionResult): PublicExecutionRequest[] {
200
+ const countedRequests = collectEnqueuedCountedPublicExecutionRequests(execResult);
170
201
  // without the reverse sort, the logs will be in a queue like fashion which is wrong
171
202
  // as the kernel processes it like a stack, popping items off and pushing them to output
172
- return [
173
- ...execResult.enqueuedPublicFunctionCalls,
174
- ...execResult.nestedExecutions.flatMap(collectEnqueuedPublicFunctionCalls),
175
- ].sort((a, b) => b.sideEffectCounter - a.sideEffectCounter);
203
+ return sortByCounter(countedRequests, false).map(r => r.request);
176
204
  }
177
205
 
178
- export function collectPublicTeardownFunctionCall(execResult: ExecutionResult): PublicCallRequest {
206
+ export function collectPublicTeardownFunctionCall(execResult: ExecutionResult): PublicExecutionRequest {
179
207
  const teardownCalls = [
180
208
  execResult.publicTeardownFunctionCall,
181
209
  ...execResult.nestedExecutions.flatMap(collectPublicTeardownFunctionCall),
@@ -189,5 +217,12 @@ export function collectPublicTeardownFunctionCall(execResult: ExecutionResult):
189
217
  throw new Error('Multiple public teardown calls detected');
190
218
  }
191
219
 
192
- return PublicCallRequest.empty();
220
+ return PublicExecutionRequest.empty();
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());
193
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';
@@ -1,4 +1,9 @@
1
- import { type FunctionCall, type SimulationError, UnencryptedFunctionL2Logs } from '@aztec/circuit-types';
1
+ import {
2
+ type FunctionCall,
3
+ PublicExecutionRequest,
4
+ type SimulationError,
5
+ UnencryptedFunctionL2Logs,
6
+ } from '@aztec/circuit-types';
2
7
  import {
3
8
  ARGS_LENGTH,
4
9
  AvmExecutionHints,
@@ -8,13 +13,12 @@ import {
8
13
  type ContractStorageUpdateRequest,
9
14
  Fr,
10
15
  Gas,
11
- type PublicCallRequest,
12
16
  } from '@aztec/circuits.js';
13
17
  import { makeAztecAddress, makeSelector } from '@aztec/circuits.js/testing';
14
18
  import { FunctionType } from '@aztec/foundation/abi';
15
19
  import { padArrayEnd } from '@aztec/foundation/collection';
16
20
 
17
- import { type PublicExecutionRequest, type PublicExecutionResult } from '../public/execution.js';
21
+ import { type PublicExecutionResult, resultToPublicCallRequest } from '../public/execution.js';
18
22
 
19
23
  export class PublicExecutionResultBuilder {
20
24
  private _executionRequest: PublicExecutionRequest;
@@ -29,7 +33,7 @@ export class PublicExecutionResultBuilder {
29
33
  this._executionRequest = executionRequest;
30
34
  }
31
35
 
32
- static fromPublicCallRequest({
36
+ static fromPublicExecutionRequest({
33
37
  request,
34
38
  returnValues = [new Fr(1n)],
35
39
  nestedExecutions = [],
@@ -37,7 +41,7 @@ export class PublicExecutionResultBuilder {
37
41
  contractStorageReads = [],
38
42
  revertReason = undefined,
39
43
  }: {
40
- request: PublicCallRequest;
44
+ request: PublicExecutionRequest;
41
45
  returnValues?: Fr[];
42
46
  nestedExecutions?: PublicExecutionResult[];
43
47
  contractStorageUpdateRequests?: ContractStorageUpdateRequest[];
@@ -74,12 +78,9 @@ export class PublicExecutionResultBuilder {
74
78
  contractStorageReads?: ContractStorageRead[];
75
79
  revertReason?: SimulationError;
76
80
  }) {
77
- const builder = new PublicExecutionResultBuilder({
78
- callContext: new CallContext(from, tx.to, tx.selector, false, false),
79
- contractAddress: tx.to,
80
- functionSelector: tx.selector,
81
- args: tx.args,
82
- });
81
+ const builder = new PublicExecutionResultBuilder(
82
+ new PublicExecutionRequest(tx.to, new CallContext(from, tx.to, tx.selector, false, false), tx.args),
83
+ );
83
84
 
84
85
  builder.withNestedExecutions(...nestedExecutions);
85
86
  builder.withContractStorageUpdateRequest(...contractStorageUpdateRequests);
@@ -122,6 +123,7 @@ export class PublicExecutionResultBuilder {
122
123
  return {
123
124
  executionRequest: this._executionRequest,
124
125
  nestedExecutions: this._nestedExecutions,
126
+ publicCallRequests: this._nestedExecutions.map(resultToPublicCallRequest),
125
127
  noteHashReadRequests: [],
126
128
  nullifierReadRequests: [],
127
129
  nullifierNonExistentReadRequests: [],