@aztec/simulator 0.23.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/acvm/deserialize.d.ts +5 -0
- package/dest/acvm/deserialize.d.ts.map +1 -1
- package/dest/acvm/deserialize.js +8 -1
- package/dest/acvm/oracle/oracle.d.ts +7 -6
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +28 -15
- package/dest/acvm/oracle/typed_oracle.d.ts +9 -11
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +11 -11
- package/dest/avm/avm_context.d.ts +4 -4
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +6 -6
- package/dest/avm/avm_execution_environment.d.ts +3 -2
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +6 -5
- package/dest/avm/avm_memory_types.d.ts +127 -37
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +98 -106
- package/dest/avm/avm_simulator.d.ts +6 -4
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +17 -19
- package/dest/avm/errors.d.ts +3 -1
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +9 -3
- package/dest/avm/fixtures/index.d.ts +21 -5
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +28 -9
- package/dest/avm/journal/host_storage.d.ts +1 -1
- package/dest/avm/journal/host_storage.d.ts.map +1 -1
- package/dest/avm/journal/host_storage.js +1 -1
- package/dest/avm/journal/journal.d.ts +78 -50
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +125 -169
- package/dest/avm/journal/nullifiers.d.ts +85 -0
- package/dest/avm/journal/nullifiers.d.ts.map +1 -0
- package/dest/avm/journal/nullifiers.js +147 -0
- package/dest/avm/journal/public_storage.d.ts +88 -0
- package/dest/avm/journal/public_storage.d.ts.map +1 -0
- package/dest/avm/journal/public_storage.js +135 -0
- package/dest/avm/journal/trace.d.ts +43 -0
- package/dest/avm/journal/trace.d.ts.map +1 -0
- package/dest/avm/journal/trace.js +204 -0
- package/dest/avm/journal/trace_types.d.ts +26 -0
- package/dest/avm/journal/trace_types.d.ts.map +1 -0
- package/dest/avm/journal/trace_types.js +6 -0
- package/dest/avm/opcodes/accrued_substate.d.ts +37 -4
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +109 -12
- package/dest/avm/opcodes/addressing_mode.d.ts +24 -0
- package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -0
- package/dest/avm/opcodes/addressing_mode.js +62 -0
- package/dest/avm/opcodes/environment_getters.d.ts +14 -13
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +1 -1
- package/dest/avm/opcodes/external_calls.js +5 -5
- package/dest/avm/opcodes/hashing.d.ts +48 -0
- package/dest/avm/opcodes/hashing.d.ts.map +1 -0
- package/dest/avm/opcodes/hashing.js +127 -0
- package/dest/avm/opcodes/instruction.d.ts +4 -4
- package/dest/avm/opcodes/instruction.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction.js +1 -1
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +5 -3
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +3 -3
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +28 -22
- package/dest/avm/serialization/instruction_serialization.d.ts +21 -16
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +23 -18
- package/dest/avm/temporary_executor_migration.d.ts +25 -0
- package/dest/avm/temporary_executor_migration.d.ts.map +1 -0
- package/dest/avm/temporary_executor_migration.js +71 -0
- package/dest/client/client_execution_context.d.ts +13 -7
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +52 -27
- package/dest/client/db_oracle.d.ts +7 -0
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/db_oracle.js +1 -1
- package/dest/client/execution_note_cache.js +1 -1
- package/dest/client/execution_result.d.ts +4 -2
- package/dest/client/execution_result.d.ts.map +1 -1
- package/dest/client/execution_result.js +1 -1
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +4 -4
- package/dest/client/simulator.d.ts +11 -6
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +21 -12
- package/dest/client/unconstrained_execution.js +2 -2
- package/dest/client/view_data_oracle.d.ts +9 -2
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +13 -5
- package/dest/public/db.d.ts +17 -4
- package/dest/public/db.d.ts.map +1 -1
- package/dest/public/execution.d.ts +9 -4
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +18 -5
- package/dest/public/executor.d.ts +7 -0
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +40 -6
- package/dest/public/public_execution_context.d.ts +5 -4
- package/dest/public/public_execution_context.d.ts.map +1 -1
- package/dest/public/public_execution_context.js +24 -13
- package/dest/public/state_actions.d.ts +1 -1
- package/dest/public/state_actions.d.ts.map +1 -1
- package/dest/public/state_actions.js +6 -7
- package/dest/test/utils.js +4 -4
- package/dest/utils.d.ts +5 -20
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +4 -21
- package/package.json +9 -6
- package/src/acvm/acvm.ts +156 -0
- package/src/acvm/acvm_types.ts +11 -0
- package/src/acvm/deserialize.ts +44 -0
- package/src/acvm/index.ts +5 -0
- package/src/acvm/oracle/debug.ts +109 -0
- package/src/acvm/oracle/index.ts +17 -0
- package/src/acvm/oracle/oracle.ts +356 -0
- package/src/acvm/oracle/typed_oracle.ts +225 -0
- package/src/acvm/serialize.ts +75 -0
- package/src/avm/avm_context.ts +63 -0
- package/src/avm/avm_execution_environment.ts +98 -0
- package/src/avm/avm_machine_state.ts +93 -0
- package/src/avm/avm_memory_types.ts +324 -0
- package/src/avm/avm_message_call_result.ts +29 -0
- package/src/avm/avm_simulator.ts +87 -0
- package/src/avm/errors.ts +57 -0
- package/src/avm/fixtures/index.ts +115 -0
- package/src/avm/journal/host_storage.ts +14 -0
- package/src/avm/journal/index.ts +2 -0
- package/src/avm/journal/journal.ts +231 -0
- package/src/avm/journal/nullifiers.ts +170 -0
- package/src/avm/journal/public_storage.ts +149 -0
- package/src/avm/journal/trace.ts +223 -0
- package/src/avm/journal/trace_types.ts +79 -0
- package/src/avm/opcodes/.eslintrc.cjs +8 -0
- package/src/avm/opcodes/accrued_substate.ts +214 -0
- package/src/avm/opcodes/addressing_mode.ts +66 -0
- package/src/avm/opcodes/arithmetic.ts +79 -0
- package/src/avm/opcodes/bitwise.ts +129 -0
- package/src/avm/opcodes/comparators.ts +69 -0
- package/src/avm/opcodes/control_flow.ts +129 -0
- package/src/avm/opcodes/environment_getters.ts +201 -0
- package/src/avm/opcodes/external_calls.ts +122 -0
- package/src/avm/opcodes/hashing.ts +170 -0
- package/src/avm/opcodes/index.ts +10 -0
- package/src/avm/opcodes/instruction.ts +64 -0
- package/src/avm/opcodes/instruction_impl.ts +52 -0
- package/src/avm/opcodes/memory.ts +194 -0
- package/src/avm/opcodes/storage.ts +79 -0
- package/src/avm/serialization/buffer_cursor.ts +109 -0
- package/src/avm/serialization/bytecode_serialization.ts +179 -0
- package/src/avm/serialization/instruction_serialization.ts +170 -0
- package/src/avm/temporary_executor_migration.ts +109 -0
- package/src/client/client_execution_context.ts +502 -0
- package/src/client/db_oracle.ts +192 -0
- package/src/client/execution_note_cache.ts +90 -0
- package/src/client/execution_result.ts +89 -0
- package/src/client/index.ts +3 -0
- package/src/client/pick_notes.ts +125 -0
- package/src/client/private_execution.ts +79 -0
- package/src/client/simulator.ts +317 -0
- package/src/client/unconstrained_execution.ts +49 -0
- package/src/client/view_data_oracle.ts +253 -0
- package/src/common/errors.ts +61 -0
- package/src/common/index.ts +3 -0
- package/src/common/packed_args_cache.ts +55 -0
- package/src/common/side_effect_counter.ts +12 -0
- package/src/index.ts +3 -0
- package/src/public/db.ts +100 -0
- package/src/public/execution.ts +161 -0
- package/src/public/executor.ts +178 -0
- package/src/public/index.ts +9 -0
- package/src/public/public_execution_context.ts +241 -0
- package/src/public/state_actions.ts +100 -0
- package/src/test/utils.ts +38 -0
- package/src/utils.ts +18 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
|
|
3
|
+
import { TracedL1toL2MessageCheck, TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js';
|
|
4
|
+
|
|
5
|
+
export class WorldStateAccessTrace {
|
|
6
|
+
public accessCounter: number;
|
|
7
|
+
//public contractCalls: Array<TracedContractCall> = [];
|
|
8
|
+
|
|
9
|
+
//public publicStorageReads: Array<TracedPublicStorageRead> = [];
|
|
10
|
+
public publicStorageReads: Map<bigint, Map<bigint, Fr[]>> = new Map();
|
|
11
|
+
//public publicStorageWrites: Array<TracedPublicStorageWrite> = [];
|
|
12
|
+
public publicStorageWrites: Map<bigint, Map<bigint, Fr[]>> = new Map();
|
|
13
|
+
|
|
14
|
+
public noteHashChecks: TracedNoteHashCheck[] = [];
|
|
15
|
+
//public newNoteHashes: TracedNoteHash[] = [];
|
|
16
|
+
public newNoteHashes: Fr[] = [];
|
|
17
|
+
public nullifierChecks: TracedNullifierCheck[] = [];
|
|
18
|
+
//public newNullifiers: TracedNullifier[] = [];
|
|
19
|
+
public newNullifiers: Fr[] = [];
|
|
20
|
+
public l1ToL2MessageChecks: TracedL1toL2MessageCheck[] = [];
|
|
21
|
+
//public archiveChecks: TracedArchiveLeafCheck[] = [];
|
|
22
|
+
|
|
23
|
+
constructor(parentTrace?: WorldStateAccessTrace) {
|
|
24
|
+
this.accessCounter = parentTrace ? parentTrace.accessCounter : 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public getAccessCounter() {
|
|
28
|
+
return this.accessCounter;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr /*, _exists: boolean*/) {
|
|
32
|
+
// TODO(4805): check if some threshold is reached for max storage reads
|
|
33
|
+
// (need access to parent length, or trace needs to be initialized with parent's contents)
|
|
34
|
+
//const traced: TracedPublicStorageRead = {
|
|
35
|
+
// callPointer: Fr.ZERO,
|
|
36
|
+
// storageAddress,
|
|
37
|
+
// slot,
|
|
38
|
+
// value,
|
|
39
|
+
// exists,
|
|
40
|
+
// counter: new Fr(this.accessCounter),
|
|
41
|
+
// endLifetime: Fr.ZERO,
|
|
42
|
+
//};
|
|
43
|
+
//this.publicStorageReads.push(traced);
|
|
44
|
+
this.journalRead(storageAddress, slot, value);
|
|
45
|
+
this.incrementAccessCounter();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public tracePublicStorageWrite(storageAddress: Fr, slot: Fr, value: Fr) {
|
|
49
|
+
// TODO(4805): check if some threshold is reached for max storage writes
|
|
50
|
+
// (need access to parent length, or trace needs to be initialized with parent's contents)
|
|
51
|
+
//const traced: TracedPublicStorageWrite = {
|
|
52
|
+
// callPointer: Fr.ZERO,
|
|
53
|
+
// storageAddress,
|
|
54
|
+
// slot,
|
|
55
|
+
// value,
|
|
56
|
+
// counter: new Fr(this.accessCounter),
|
|
57
|
+
// endLifetime: Fr.ZERO,
|
|
58
|
+
//};
|
|
59
|
+
//this.publicStorageWrites.push(traced);
|
|
60
|
+
this.journalWrite(storageAddress, slot, value);
|
|
61
|
+
this.incrementAccessCounter();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public traceNoteHashCheck(storageAddress: Fr, noteHash: Fr, exists: boolean, leafIndex: Fr) {
|
|
65
|
+
const traced: TracedNoteHashCheck = {
|
|
66
|
+
callPointer: Fr.ZERO, // FIXME
|
|
67
|
+
storageAddress,
|
|
68
|
+
noteHash,
|
|
69
|
+
exists,
|
|
70
|
+
counter: new Fr(this.accessCounter),
|
|
71
|
+
endLifetime: Fr.ZERO,
|
|
72
|
+
leafIndex,
|
|
73
|
+
};
|
|
74
|
+
this.noteHashChecks.push(traced);
|
|
75
|
+
this.incrementAccessCounter();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public traceNewNoteHash(_storageAddress: Fr, noteHash: Fr) {
|
|
79
|
+
// TODO(4805): check if some threshold is reached for max new note hash
|
|
80
|
+
//const traced: TracedNoteHash = {
|
|
81
|
+
// callPointer: Fr.ZERO,
|
|
82
|
+
// storageAddress,
|
|
83
|
+
// noteHash,
|
|
84
|
+
// counter: new Fr(this.accessCounter),
|
|
85
|
+
// endLifetime: Fr.ZERO,
|
|
86
|
+
//};
|
|
87
|
+
//this.newNoteHashes.push(traced);
|
|
88
|
+
this.newNoteHashes.push(noteHash);
|
|
89
|
+
this.incrementAccessCounter();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public traceNullifierCheck(storageAddress: Fr, nullifier: Fr, exists: boolean, isPending: boolean, leafIndex: Fr) {
|
|
93
|
+
// TODO(4805): check if some threshold is reached for max new nullifier
|
|
94
|
+
const traced: TracedNullifierCheck = {
|
|
95
|
+
callPointer: Fr.ZERO, // FIXME
|
|
96
|
+
storageAddress,
|
|
97
|
+
nullifier,
|
|
98
|
+
exists,
|
|
99
|
+
counter: new Fr(this.accessCounter),
|
|
100
|
+
endLifetime: Fr.ZERO,
|
|
101
|
+
isPending,
|
|
102
|
+
leafIndex,
|
|
103
|
+
};
|
|
104
|
+
this.nullifierChecks.push(traced);
|
|
105
|
+
this.incrementAccessCounter();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public traceNewNullifier(_storageAddress: Fr, nullifier: Fr) {
|
|
109
|
+
// TODO(4805): check if some threshold is reached for max new nullifier
|
|
110
|
+
//const traced: TracedNullifier = {
|
|
111
|
+
// callPointer: Fr.ZERO,
|
|
112
|
+
// storageAddress,
|
|
113
|
+
// nullifier,
|
|
114
|
+
// counter: new Fr(this.accessCounter),
|
|
115
|
+
// endLifetime: Fr.ZERO,
|
|
116
|
+
//};
|
|
117
|
+
//this.newNullifiers.push(traced);
|
|
118
|
+
this.newNullifiers.push(nullifier);
|
|
119
|
+
this.incrementAccessCounter();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public traceL1ToL2MessageCheck(msgHash: Fr, msgLeafIndex: Fr, exists: boolean) {
|
|
123
|
+
// TODO(4805): check if some threshold is reached for max message reads
|
|
124
|
+
const traced: TracedL1toL2MessageCheck = {
|
|
125
|
+
//callPointer: Fr.ZERO, // FIXME
|
|
126
|
+
leafIndex: msgLeafIndex,
|
|
127
|
+
msgHash: msgHash,
|
|
128
|
+
exists: exists,
|
|
129
|
+
//endLifetime: Fr.ZERO, // FIXME
|
|
130
|
+
};
|
|
131
|
+
this.l1ToL2MessageChecks.push(traced);
|
|
132
|
+
this.incrementAccessCounter();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private incrementAccessCounter() {
|
|
136
|
+
this.accessCounter++;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Merges another trace into this one
|
|
141
|
+
*
|
|
142
|
+
* - Public state journals (r/w logs), with the accessing being appended in chronological order
|
|
143
|
+
* - Utxo objects are concatenated
|
|
144
|
+
*
|
|
145
|
+
* @param incomingTrace - the incoming trace to merge into this instance
|
|
146
|
+
*/
|
|
147
|
+
public acceptAndMerge(incomingTrace: WorldStateAccessTrace) {
|
|
148
|
+
// Merge storage read and write journals
|
|
149
|
+
mergeContractJournalMaps(this.publicStorageReads, incomingTrace.publicStorageReads);
|
|
150
|
+
mergeContractJournalMaps(this.publicStorageWrites, incomingTrace.publicStorageWrites);
|
|
151
|
+
// Merge new note hashes and nullifiers
|
|
152
|
+
this.noteHashChecks = this.noteHashChecks.concat(incomingTrace.noteHashChecks);
|
|
153
|
+
this.newNoteHashes = this.newNoteHashes.concat(incomingTrace.newNoteHashes);
|
|
154
|
+
this.nullifierChecks = this.nullifierChecks.concat(incomingTrace.nullifierChecks);
|
|
155
|
+
this.newNullifiers = this.newNullifiers.concat(incomingTrace.newNullifiers);
|
|
156
|
+
this.l1ToL2MessageChecks = this.l1ToL2MessageChecks.concat(incomingTrace.l1ToL2MessageChecks);
|
|
157
|
+
// it is assumed that the incoming trace was initialized with this as parent, so accept counter
|
|
158
|
+
this.accessCounter = incomingTrace.accessCounter;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* We want to keep track of all performed reads in the journal
|
|
163
|
+
* This information is hinted to the avm circuit
|
|
164
|
+
|
|
165
|
+
* @param contractAddress -
|
|
166
|
+
* @param key -
|
|
167
|
+
* @param value -
|
|
168
|
+
*/
|
|
169
|
+
journalUpdate(map: Map<bigint, Map<bigint, Fr[]>>, contractAddress: Fr, key: Fr, value: Fr): void {
|
|
170
|
+
let contractMap = map.get(contractAddress.toBigInt());
|
|
171
|
+
if (!contractMap) {
|
|
172
|
+
contractMap = new Map<bigint, Array<Fr>>();
|
|
173
|
+
map.set(contractAddress.toBigInt(), contractMap);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let accessArray = contractMap.get(key.toBigInt());
|
|
177
|
+
if (!accessArray) {
|
|
178
|
+
accessArray = new Array<Fr>();
|
|
179
|
+
contractMap.set(key.toBigInt(), accessArray);
|
|
180
|
+
}
|
|
181
|
+
accessArray.push(value);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Create an instance of journalUpdate that appends to the read array
|
|
185
|
+
private journalRead = this.journalUpdate.bind(this, this.publicStorageReads);
|
|
186
|
+
// Create an instance of journalUpdate that appends to the writes array
|
|
187
|
+
private journalWrite = this.journalUpdate.bind(this, this.publicStorageWrites);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Merges two contract journalling maps together
|
|
192
|
+
* For read maps, we just append the childMap arrays into the host map arrays, as the order is important
|
|
193
|
+
*
|
|
194
|
+
* @param hostMap - The map to be merged into
|
|
195
|
+
* @param childMap - The map to be merged from
|
|
196
|
+
*/
|
|
197
|
+
function mergeContractJournalMaps(hostMap: Map<bigint, Map<bigint, Fr[]>>, childMap: Map<bigint, Map<bigint, Fr[]>>) {
|
|
198
|
+
for (const [key, value] of childMap) {
|
|
199
|
+
const map1Value = hostMap.get(key);
|
|
200
|
+
if (!map1Value) {
|
|
201
|
+
hostMap.set(key, value);
|
|
202
|
+
} else {
|
|
203
|
+
mergeStorageJournalMaps(map1Value, value);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Merge two storage journalling maps together (for a particular contract).
|
|
210
|
+
*
|
|
211
|
+
* @param hostMap - The map to be merge into
|
|
212
|
+
* @param childMap - The map to be merged from
|
|
213
|
+
*/
|
|
214
|
+
function mergeStorageJournalMaps(hostMap: Map<bigint, Fr[]>, childMap: Map<bigint, Fr[]>) {
|
|
215
|
+
for (const [key, value] of childMap) {
|
|
216
|
+
const readArr = hostMap.get(key);
|
|
217
|
+
if (!readArr) {
|
|
218
|
+
hostMap.set(key, value);
|
|
219
|
+
} else {
|
|
220
|
+
hostMap.set(key, readArr?.concat(...value));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
|
|
3
|
+
//export type TracedContractCall = {
|
|
4
|
+
// callPointer: Fr;
|
|
5
|
+
// address: Fr;
|
|
6
|
+
// storageAddress: Fr;
|
|
7
|
+
// endLifetime: Fr;
|
|
8
|
+
//};
|
|
9
|
+
//
|
|
10
|
+
//export type TracedPublicStorageRead = {
|
|
11
|
+
// callPointer: Fr;
|
|
12
|
+
// storageAddress: Fr;
|
|
13
|
+
// exists: boolean;
|
|
14
|
+
// slot: Fr;
|
|
15
|
+
// value: Fr;
|
|
16
|
+
// counter: Fr;
|
|
17
|
+
// endLifetime: Fr;
|
|
18
|
+
//};
|
|
19
|
+
//
|
|
20
|
+
//export type TracedPublicStorageWrite = {
|
|
21
|
+
// callPointer: Fr;
|
|
22
|
+
// storageAddress: Fr;
|
|
23
|
+
// slot: Fr;
|
|
24
|
+
// value: Fr;
|
|
25
|
+
// counter: Fr;
|
|
26
|
+
// endLifetime: Fr;
|
|
27
|
+
//};
|
|
28
|
+
//
|
|
29
|
+
export type TracedNoteHashCheck = {
|
|
30
|
+
callPointer: Fr;
|
|
31
|
+
storageAddress: Fr;
|
|
32
|
+
leafIndex: Fr;
|
|
33
|
+
noteHash: Fr;
|
|
34
|
+
exists: boolean;
|
|
35
|
+
counter: Fr;
|
|
36
|
+
endLifetime: Fr;
|
|
37
|
+
};
|
|
38
|
+
//
|
|
39
|
+
//export type TracedNoteHash = {
|
|
40
|
+
// callPointer: Fr;
|
|
41
|
+
// storageAddress: Fr;
|
|
42
|
+
// noteHash: Fr;
|
|
43
|
+
// counter: Fr;
|
|
44
|
+
// endLifetime: Fr;
|
|
45
|
+
//};
|
|
46
|
+
|
|
47
|
+
export type TracedNullifierCheck = {
|
|
48
|
+
callPointer: Fr;
|
|
49
|
+
storageAddress: Fr;
|
|
50
|
+
nullifier: Fr;
|
|
51
|
+
exists: boolean;
|
|
52
|
+
counter: Fr;
|
|
53
|
+
endLifetime: Fr;
|
|
54
|
+
// the fields below are relevant only to the public kernel
|
|
55
|
+
// and are therefore omitted from VM inputs
|
|
56
|
+
isPending: boolean;
|
|
57
|
+
leafIndex: Fr;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
//export type TracedNullifier = {
|
|
61
|
+
// callPointer: Fr;
|
|
62
|
+
// storageAddress: Fr;
|
|
63
|
+
// nullifier: Fr;
|
|
64
|
+
// counter: Fr;
|
|
65
|
+
// endLifetime: Fr;
|
|
66
|
+
//};
|
|
67
|
+
|
|
68
|
+
export type TracedL1toL2MessageCheck = {
|
|
69
|
+
//callPointer: Fr;
|
|
70
|
+
leafIndex: Fr;
|
|
71
|
+
msgHash: Fr;
|
|
72
|
+
exists: boolean;
|
|
73
|
+
//endLifetime: Fr;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//export type TracedArchiveLeafCheck = {
|
|
77
|
+
// leafIndex: Fr;
|
|
78
|
+
// leaf: Fr;
|
|
79
|
+
//};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { AvmContext } from '../avm_context.js';
|
|
2
|
+
import { Uint8 } from '../avm_memory_types.js';
|
|
3
|
+
import { InstructionExecutionError } from '../errors.js';
|
|
4
|
+
import { NullifierCollisionError } from '../journal/nullifiers.js';
|
|
5
|
+
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
6
|
+
import { Addressing } from './addressing_mode.js';
|
|
7
|
+
import { Instruction } from './instruction.js';
|
|
8
|
+
import { StaticCallStorageAlterError } from './storage.js';
|
|
9
|
+
|
|
10
|
+
export class NoteHashExists extends Instruction {
|
|
11
|
+
static type: string = 'NOTEHASHEXISTS';
|
|
12
|
+
static readonly opcode: Opcode = Opcode.NOTEHASHEXISTS;
|
|
13
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
14
|
+
static readonly wireFormat = [
|
|
15
|
+
OperandType.UINT8,
|
|
16
|
+
OperandType.UINT8,
|
|
17
|
+
OperandType.UINT32,
|
|
18
|
+
OperandType.UINT32,
|
|
19
|
+
OperandType.UINT32,
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
private indirect: number,
|
|
24
|
+
private noteHashOffset: number,
|
|
25
|
+
private leafIndexOffset: number,
|
|
26
|
+
private existsOffset: number,
|
|
27
|
+
) {
|
|
28
|
+
super();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async execute(context: AvmContext): Promise<void> {
|
|
32
|
+
// Note that this instruction accepts any type in memory, and converts to Field.
|
|
33
|
+
const noteHash = context.machineState.memory.get(this.noteHashOffset).toFr();
|
|
34
|
+
const leafIndex = context.machineState.memory.get(this.leafIndexOffset).toFr();
|
|
35
|
+
|
|
36
|
+
const exists = await context.persistableState.checkNoteHashExists(
|
|
37
|
+
context.environment.storageAddress,
|
|
38
|
+
noteHash,
|
|
39
|
+
leafIndex,
|
|
40
|
+
);
|
|
41
|
+
context.machineState.memory.set(this.existsOffset, exists ? new Uint8(1) : new Uint8(0));
|
|
42
|
+
|
|
43
|
+
context.machineState.incrementPc();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class EmitNoteHash extends Instruction {
|
|
48
|
+
static type: string = 'EMITNOTEHASH';
|
|
49
|
+
static readonly opcode: Opcode = Opcode.EMITNOTEHASH;
|
|
50
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
51
|
+
static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32];
|
|
52
|
+
|
|
53
|
+
constructor(private indirect: number, private noteHashOffset: number) {
|
|
54
|
+
super();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async execute(context: AvmContext): Promise<void> {
|
|
58
|
+
if (context.environment.isStaticCall) {
|
|
59
|
+
throw new StaticCallStorageAlterError();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const noteHash = context.machineState.memory.get(this.noteHashOffset).toFr();
|
|
63
|
+
context.persistableState.writeNoteHash(noteHash);
|
|
64
|
+
|
|
65
|
+
context.machineState.incrementPc();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class NullifierExists extends Instruction {
|
|
70
|
+
static type: string = 'NULLIFIEREXISTS';
|
|
71
|
+
static readonly opcode: Opcode = Opcode.NULLIFIEREXISTS;
|
|
72
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
73
|
+
static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32];
|
|
74
|
+
|
|
75
|
+
constructor(private indirect: number, private nullifierOffset: number, private existsOffset: number) {
|
|
76
|
+
super();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async execute(context: AvmContext): Promise<void> {
|
|
80
|
+
const nullifier = context.machineState.memory.get(this.nullifierOffset).toFr();
|
|
81
|
+
const exists = await context.persistableState.checkNullifierExists(context.environment.storageAddress, nullifier);
|
|
82
|
+
|
|
83
|
+
context.machineState.memory.set(this.existsOffset, exists ? new Uint8(1) : new Uint8(0));
|
|
84
|
+
|
|
85
|
+
context.machineState.incrementPc();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class EmitNullifier extends Instruction {
|
|
90
|
+
static type: string = 'EMITNULLIFIER';
|
|
91
|
+
static readonly opcode: Opcode = Opcode.EMITNULLIFIER;
|
|
92
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
93
|
+
static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32];
|
|
94
|
+
|
|
95
|
+
constructor(private indirect: number, private nullifierOffset: number) {
|
|
96
|
+
super();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async execute(context: AvmContext): Promise<void> {
|
|
100
|
+
if (context.environment.isStaticCall) {
|
|
101
|
+
throw new StaticCallStorageAlterError();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const nullifier = context.machineState.memory.get(this.nullifierOffset).toFr();
|
|
105
|
+
try {
|
|
106
|
+
await context.persistableState.writeNullifier(context.environment.storageAddress, nullifier);
|
|
107
|
+
} catch (e) {
|
|
108
|
+
if (e instanceof NullifierCollisionError) {
|
|
109
|
+
// Error is known/expected, raise as InstructionExecutionError that the will lead the simulator to revert this call
|
|
110
|
+
throw new InstructionExecutionError(
|
|
111
|
+
`Attempted to emit duplicate nullifier ${nullifier} (storage address: ${context.environment.storageAddress}).`,
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
context.machineState.incrementPc();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export class L1ToL2MessageExists extends Instruction {
|
|
123
|
+
static type: string = 'L1TOL2MSGEXISTS';
|
|
124
|
+
static readonly opcode: Opcode = Opcode.L1TOL2MSGEXISTS;
|
|
125
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
126
|
+
static readonly wireFormat = [
|
|
127
|
+
OperandType.UINT8,
|
|
128
|
+
OperandType.UINT8,
|
|
129
|
+
OperandType.UINT32,
|
|
130
|
+
OperandType.UINT32,
|
|
131
|
+
OperandType.UINT32,
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
constructor(
|
|
135
|
+
private indirect: number,
|
|
136
|
+
private msgHashOffset: number,
|
|
137
|
+
private msgLeafIndexOffset: number,
|
|
138
|
+
private existsOffset: number,
|
|
139
|
+
) {
|
|
140
|
+
super();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async execute(context: AvmContext): Promise<void> {
|
|
144
|
+
const msgHash = context.machineState.memory.get(this.msgHashOffset).toFr();
|
|
145
|
+
const msgLeafIndex = context.machineState.memory.get(this.msgLeafIndexOffset).toFr();
|
|
146
|
+
const exists = await context.persistableState.checkL1ToL2MessageExists(msgHash, msgLeafIndex);
|
|
147
|
+
context.machineState.memory.set(this.existsOffset, exists ? new Uint8(1) : new Uint8(0));
|
|
148
|
+
|
|
149
|
+
context.machineState.incrementPc();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export class EmitUnencryptedLog extends Instruction {
|
|
154
|
+
static type: string = 'EMITUNENCRYPTEDLOG';
|
|
155
|
+
static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG;
|
|
156
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
157
|
+
static readonly wireFormat = [
|
|
158
|
+
OperandType.UINT8,
|
|
159
|
+
OperandType.UINT8,
|
|
160
|
+
OperandType.UINT32,
|
|
161
|
+
OperandType.UINT32,
|
|
162
|
+
OperandType.UINT32,
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
constructor(
|
|
166
|
+
private indirect: number,
|
|
167
|
+
private eventSelectorOffset: number,
|
|
168
|
+
private logOffset: number,
|
|
169
|
+
private logSize: number,
|
|
170
|
+
) {
|
|
171
|
+
super();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async execute(context: AvmContext): Promise<void> {
|
|
175
|
+
if (context.environment.isStaticCall) {
|
|
176
|
+
throw new StaticCallStorageAlterError();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const [eventSelectorOffset, logOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
180
|
+
[this.eventSelectorOffset, this.logOffset],
|
|
181
|
+
context.machineState.memory,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const contractAddress = context.environment.address;
|
|
185
|
+
const event = context.machineState.memory.get(eventSelectorOffset).toFr();
|
|
186
|
+
const log = context.machineState.memory.getSlice(logOffset, this.logSize).map(f => f.toFr());
|
|
187
|
+
context.persistableState.writeLog(contractAddress, event, log);
|
|
188
|
+
|
|
189
|
+
context.machineState.incrementPc();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export class SendL2ToL1Message extends Instruction {
|
|
194
|
+
static type: string = 'SENDL2TOL1MSG';
|
|
195
|
+
static readonly opcode: Opcode = Opcode.SENDL2TOL1MSG;
|
|
196
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
197
|
+
static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32];
|
|
198
|
+
|
|
199
|
+
constructor(private indirect: number, private recipientOffset: number, private contentOffset: number) {
|
|
200
|
+
super();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async execute(context: AvmContext): Promise<void> {
|
|
204
|
+
if (context.environment.isStaticCall) {
|
|
205
|
+
throw new StaticCallStorageAlterError();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const recipient = context.machineState.memory.get(this.recipientOffset).toFr();
|
|
209
|
+
const content = context.machineState.memory.get(this.contentOffset).toFr();
|
|
210
|
+
context.persistableState.writeL1Message(recipient, content);
|
|
211
|
+
|
|
212
|
+
context.machineState.incrementPc();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { strict as assert } from 'assert';
|
|
2
|
+
|
|
3
|
+
import { TaggedMemory, TypeTag } from '../avm_memory_types.js';
|
|
4
|
+
|
|
5
|
+
export enum AddressingMode {
|
|
6
|
+
DIRECT,
|
|
7
|
+
INDIRECT,
|
|
8
|
+
INDIRECT_PLUS_CONSTANT, // Not implemented yet.
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A class to represent the addressing mode of an instruction. */
|
|
12
|
+
export class Addressing {
|
|
13
|
+
public constructor(
|
|
14
|
+
/** The addressing mode for each operand. The length of this array is the number of operands of the instruction. */
|
|
15
|
+
private readonly modePerOperand: AddressingMode[],
|
|
16
|
+
) {
|
|
17
|
+
assert(modePerOperand.length <= 8, 'At most 8 operands are supported');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public static fromWire(wireModes: number): Addressing {
|
|
21
|
+
// The modes are stored in the wire format as a byte, with each bit representing the mode for an operand.
|
|
22
|
+
// The least significant bit represents the zeroth operand, and the most significant bit represents the last operand.
|
|
23
|
+
const modes = new Array<AddressingMode>(8);
|
|
24
|
+
for (let i = 0; i < 8; i++) {
|
|
25
|
+
modes[i] = (wireModes & (1 << i)) === 0 ? AddressingMode.DIRECT : AddressingMode.INDIRECT;
|
|
26
|
+
}
|
|
27
|
+
return new Addressing(modes);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public toWire(): number {
|
|
31
|
+
// The modes are stored in the wire format as a byte, with each bit representing the mode for an operand.
|
|
32
|
+
// The least significant bit represents the zeroth operand, and the least significant bit represents the last operand.
|
|
33
|
+
let wire: number = 0;
|
|
34
|
+
for (let i = 0; i < 8; i++) {
|
|
35
|
+
if (this.modePerOperand[i] === AddressingMode.INDIRECT) {
|
|
36
|
+
wire |= 1 << i;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return wire;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolves the offsets using the addressing mode.
|
|
44
|
+
* @param offsets The offsets to resolve.
|
|
45
|
+
* @param mem The memory to use for resolution.
|
|
46
|
+
* @returns The resolved offsets. The length of the returned array is the same as the length of the input array.
|
|
47
|
+
*/
|
|
48
|
+
public resolve(offsets: number[], mem: TaggedMemory): number[] {
|
|
49
|
+
assert(offsets.length <= this.modePerOperand.length);
|
|
50
|
+
const resolved = new Array(offsets.length);
|
|
51
|
+
for (const [i, offset] of offsets.entries()) {
|
|
52
|
+
switch (this.modePerOperand[i]) {
|
|
53
|
+
case AddressingMode.INDIRECT:
|
|
54
|
+
mem.checkTag(TypeTag.UINT32, offset);
|
|
55
|
+
resolved[i] = Number(mem.get(offset).toBigInt());
|
|
56
|
+
break;
|
|
57
|
+
case AddressingMode.DIRECT:
|
|
58
|
+
resolved[i] = offset;
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
throw new Error(`Unimplemented addressing mode: ${AddressingMode[this.modePerOperand[i]]}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return resolved;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AvmContext } from '../avm_context.js';
|
|
2
|
+
import { Opcode } from '../serialization/instruction_serialization.js';
|
|
3
|
+
import { ThreeOperandInstruction } from './instruction_impl.js';
|
|
4
|
+
|
|
5
|
+
export class Add extends ThreeOperandInstruction {
|
|
6
|
+
static readonly type: string = 'ADD';
|
|
7
|
+
static readonly opcode = Opcode.ADD;
|
|
8
|
+
|
|
9
|
+
constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
|
|
10
|
+
super(indirect, inTag, aOffset, bOffset, dstOffset);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async execute(context: AvmContext): Promise<void> {
|
|
14
|
+
const a = context.machineState.memory.get(this.aOffset);
|
|
15
|
+
const b = context.machineState.memory.get(this.bOffset);
|
|
16
|
+
|
|
17
|
+
const dest = a.add(b);
|
|
18
|
+
context.machineState.memory.set(this.dstOffset, dest);
|
|
19
|
+
|
|
20
|
+
context.machineState.incrementPc();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class Sub extends ThreeOperandInstruction {
|
|
25
|
+
static readonly type: string = 'SUB';
|
|
26
|
+
static readonly opcode = Opcode.SUB;
|
|
27
|
+
|
|
28
|
+
constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
|
|
29
|
+
super(indirect, inTag, aOffset, bOffset, dstOffset);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async execute(context: AvmContext): Promise<void> {
|
|
33
|
+
const a = context.machineState.memory.get(this.aOffset);
|
|
34
|
+
const b = context.machineState.memory.get(this.bOffset);
|
|
35
|
+
|
|
36
|
+
const dest = a.sub(b);
|
|
37
|
+
context.machineState.memory.set(this.dstOffset, dest);
|
|
38
|
+
|
|
39
|
+
context.machineState.incrementPc();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class Mul extends ThreeOperandInstruction {
|
|
44
|
+
static type: string = 'MUL';
|
|
45
|
+
static readonly opcode = Opcode.MUL;
|
|
46
|
+
|
|
47
|
+
constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
|
|
48
|
+
super(indirect, inTag, aOffset, bOffset, dstOffset);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async execute(context: AvmContext): Promise<void> {
|
|
52
|
+
const a = context.machineState.memory.get(this.aOffset);
|
|
53
|
+
const b = context.machineState.memory.get(this.bOffset);
|
|
54
|
+
|
|
55
|
+
const dest = a.mul(b);
|
|
56
|
+
context.machineState.memory.set(this.dstOffset, dest);
|
|
57
|
+
|
|
58
|
+
context.machineState.incrementPc();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class Div extends ThreeOperandInstruction {
|
|
63
|
+
static type: string = 'DIV';
|
|
64
|
+
static readonly opcode = Opcode.DIV;
|
|
65
|
+
|
|
66
|
+
constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
|
|
67
|
+
super(indirect, inTag, aOffset, bOffset, dstOffset);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async execute(context: AvmContext): Promise<void> {
|
|
71
|
+
const a = context.machineState.memory.get(this.aOffset);
|
|
72
|
+
const b = context.machineState.memory.get(this.bOffset);
|
|
73
|
+
|
|
74
|
+
const dest = a.div(b);
|
|
75
|
+
context.machineState.memory.set(this.dstOffset, dest);
|
|
76
|
+
|
|
77
|
+
context.machineState.incrementPc();
|
|
78
|
+
}
|
|
79
|
+
}
|