@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.
- package/dest/acvm/acvm.d.ts +1 -1
- package/dest/acvm/acvm.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.d.ts +5 -5
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +13 -16
- package/dest/acvm/oracle/typed_oracle.d.ts +12 -9
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +6 -6
- package/dest/acvm/serialize.d.ts +0 -11
- package/dest/acvm/serialize.d.ts.map +1 -1
- package/dest/acvm/serialize.js +1 -26
- package/dest/avm/avm_gas.d.ts.map +1 -1
- package/dest/avm/avm_gas.js +2 -1
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +2 -2
- package/dest/avm/opcodes/commitment.d.ts +16 -0
- package/dest/avm/opcodes/commitment.d.ts.map +1 -0
- package/dest/avm/opcodes/commitment.js +50 -0
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +3 -1
- package/dest/avm/serialization/instruction_serialization.d.ts +4 -3
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +6 -5
- package/dest/client/client_execution_context.d.ts +20 -17
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +42 -45
- package/dest/client/db_oracle.d.ts +4 -3
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/execution_note_cache.d.ts +17 -13
- package/dest/client/execution_note_cache.d.ts.map +1 -1
- package/dest/client/execution_note_cache.js +65 -26
- package/dest/client/execution_result.d.ts +15 -8
- package/dest/client/execution_result.d.ts.map +1 -1
- package/dest/client/execution_result.js +40 -16
- package/dest/client/private_execution.js +3 -3
- package/dest/client/simulator.d.ts +7 -6
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +14 -12
- package/dest/client/test_utils.d.ts +9 -0
- package/dest/client/test_utils.d.ts.map +1 -0
- package/dest/client/test_utils.js +21 -0
- package/dest/client/view_data_oracle.d.ts +2 -1
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +4 -3
- package/dest/index.d.ts +0 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/mocks/fixtures.d.ts +5 -5
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +6 -9
- package/dest/public/abstract_phase_manager.d.ts +4 -5
- package/dest/public/abstract_phase_manager.d.ts.map +1 -1
- package/dest/public/abstract_phase_manager.js +17 -84
- package/dest/public/execution.d.ts +8 -10
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +10 -1
- package/dest/public/executor.d.ts +6 -2
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +12 -4
- package/dest/public/executor_metrics.d.ts +10 -0
- package/dest/public/executor_metrics.d.ts.map +1 -0
- package/dest/public/executor_metrics.js +32 -0
- package/dest/public/fee_payment.d.ts +2 -2
- package/dest/public/fee_payment.d.ts.map +1 -1
- package/dest/public/fee_payment.js +9 -10
- package/dest/public/hints_builder.d.ts.map +1 -1
- package/dest/public/hints_builder.js +1 -1
- package/dest/public/index.d.ts +1 -1
- package/dest/public/index.d.ts.map +1 -1
- package/dest/public/index.js +1 -1
- package/dest/public/public_processor.d.ts +3 -3
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +33 -14
- package/dest/public/public_processor_metrics.d.ts +19 -0
- package/dest/public/public_processor_metrics.d.ts.map +1 -0
- package/dest/public/public_processor_metrics.js +57 -0
- package/dest/public/side_effect_trace.d.ts +1 -0
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +9 -9
- package/package.json +9 -9
- package/src/acvm/acvm.ts +1 -1
- package/src/acvm/oracle/oracle.ts +13 -30
- package/src/acvm/oracle/typed_oracle.ts +12 -31
- package/src/acvm/serialize.ts +0 -29
- package/src/avm/avm_gas.ts +1 -0
- package/src/avm/fixtures/index.ts +1 -0
- package/src/avm/opcodes/commitment.ts +66 -0
- package/src/avm/serialization/bytecode_serialization.ts +2 -0
- package/src/avm/serialization/instruction_serialization.ts +2 -1
- package/src/client/client_execution_context.ts +51 -49
- package/src/client/db_oracle.ts +9 -3
- package/src/client/execution_note_cache.ts +76 -25
- package/src/client/execution_result.ts +54 -19
- package/src/client/private_execution.ts +2 -2
- package/src/client/simulator.ts +18 -14
- package/src/client/test_utils.ts +30 -0
- package/src/client/view_data_oracle.ts +2 -1
- package/src/index.ts +0 -1
- package/src/mocks/fixtures.ts +13 -11
- package/src/public/abstract_phase_manager.ts +23 -104
- package/src/public/execution.ts +30 -14
- package/src/public/executor.ts +18 -4
- package/src/public/executor_metrics.ts +48 -0
- package/src/public/fee_payment.ts +8 -10
- package/src/public/hints_builder.ts +2 -2
- package/src/public/index.ts +1 -1
- package/src/public/public_processor.ts +46 -15
- package/src/public/public_processor_metrics.ts +90 -0
- package/src/public/side_effect_trace.ts +13 -7
- package/dest/utils.d.ts +0 -12
- package/dest/utils.d.ts.map +0 -1
- package/dest/utils.js +0 -11
- 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
|
-
|
|
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
|
|
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
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
46
|
-
*
|
|
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,
|
|
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.
|
|
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
|
|
56
|
-
if (!
|
|
57
|
-
const
|
|
58
|
-
const noteIndexToRemove =
|
|
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
|
-
|
|
103
|
+
|
|
104
|
+
const note = notesInContract.splice(noteIndexToRemove, 1)[0];
|
|
63
105
|
nullifiedNoteHashCounter = note.counter;
|
|
64
|
-
this.
|
|
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.
|
|
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
|
|
127
|
+
* @param noteHash - A hash of the note.
|
|
85
128
|
**/
|
|
86
|
-
public checkNoteExists(contractAddress: AztecAddress,
|
|
87
|
-
const notes = this.
|
|
88
|
-
return notes.some(n => n.note.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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:
|
|
76
|
+
enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[];
|
|
67
77
|
/** Public function execution requested for teardown */
|
|
68
|
-
publicTeardownFunctionCall:
|
|
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
|
|
93
|
-
execResult
|
|
94
|
-
|
|
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
|
-
|
|
118
|
+
noteHashNullifierCounterMap: Map<number, number>,
|
|
119
|
+
minRevertibleSideEffectCounter: number,
|
|
106
120
|
): CountedLog<EncryptedL2NoteLog>[] {
|
|
107
121
|
return [
|
|
108
|
-
execResult.noteEncryptedLogs.filter(noteLog =>
|
|
109
|
-
|
|
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
|
|
120
|
-
const
|
|
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):
|
|
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):
|
|
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
|
|
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
|
|
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
|
-
|
|
85
|
+
noteHashNullifierCounterMap,
|
|
86
86
|
vk: Buffer.from(artifact.verificationKey!, 'hex'),
|
|
87
87
|
nestedExecutions,
|
|
88
88
|
enqueuedPublicFunctionCalls,
|
package/src/client/simulator.ts
CHANGED
|
@@ -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
|
|
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 [
|
|
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
|
-
|
|
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
|
|
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
|
|
214
|
-
|
|
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
|
|
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
package/src/mocks/fixtures.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
79
|
-
|
|
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: [],
|