@aztec/simulator 0.65.2 → 0.67.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.js +3 -3
- package/dest/acvm/oracle/oracle.d.ts +1 -4
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +3 -19
- package/dest/acvm/oracle/typed_oracle.d.ts +2 -7
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +3 -12
- package/dest/acvm/serialize.js +2 -2
- package/dest/avm/avm_context.d.ts +2 -2
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +3 -4
- package/dest/avm/avm_execution_environment.d.ts +4 -6
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +8 -13
- package/dest/avm/avm_memory_types.d.ts +2 -2
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +7 -7
- package/dest/avm/avm_simulator.d.ts +3 -3
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +26 -16
- package/dest/avm/avm_tree.d.ts +31 -14
- package/dest/avm/avm_tree.d.ts.map +1 -1
- package/dest/avm/avm_tree.js +34 -40
- package/dest/avm/errors.d.ts +3 -3
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +8 -15
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +4 -4
- package/dest/avm/journal/journal.d.ts +15 -4
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +121 -36
- package/dest/avm/opcodes/environment_getters.d.ts +10 -11
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +12 -15
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +4 -11
- package/dest/avm/opcodes/misc.d.ts.map +1 -1
- package/dest/avm/opcodes/misc.js +3 -3
- package/dest/client/client_execution_context.d.ts +6 -33
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +18 -54
- package/dest/client/db_oracle.d.ts +2 -2
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/execution_note_cache.d.ts +9 -1
- package/dest/client/execution_note_cache.d.ts.map +1 -1
- package/dest/client/execution_note_cache.js +10 -3
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +5 -7
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +4 -4
- package/dest/client/unconstrained_execution.d.ts.map +1 -1
- package/dest/client/unconstrained_execution.js +3 -3
- package/dest/client/view_data_oracle.d.ts +2 -2
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +5 -6
- package/dest/common/debug_fn_name.d.ts +2 -2
- package/dest/common/debug_fn_name.d.ts.map +1 -1
- package/dest/common/debug_fn_name.js +8 -14
- package/dest/providers/acvm_native.js +4 -4
- package/dest/providers/factory.d.ts +2 -2
- package/dest/providers/factory.d.ts.map +1 -1
- package/dest/providers/factory.js +4 -4
- package/dest/public/enqueued_call_side_effect_trace.d.ts +11 -23
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +51 -72
- package/dest/public/executor_metrics.d.ts.map +1 -1
- package/dest/public/executor_metrics.js +2 -5
- package/dest/public/fixtures/index.d.ts +25 -7
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +20 -17
- package/dest/public/index.d.ts +0 -1
- package/dest/public/index.d.ts.map +1 -1
- package/dest/public/index.js +1 -2
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +30 -16
- package/dest/public/public_processor.d.ts +7 -8
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +37 -26
- package/dest/public/public_processor_metrics.d.ts +1 -1
- package/dest/public/public_processor_metrics.d.ts.map +1 -1
- package/dest/public/public_tx_context.d.ts +13 -14
- package/dest/public/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_context.js +63 -54
- package/dest/public/public_tx_simulator.d.ts +2 -2
- package/dest/public/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator.js +43 -25
- package/dest/public/side_effect_trace_interface.d.ts +4 -17
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/public/transitional_adapters.d.ts +2 -6
- package/dest/public/transitional_adapters.d.ts.map +1 -1
- package/dest/public/transitional_adapters.js +29 -88
- package/package.json +16 -9
- package/src/acvm/acvm.ts +2 -2
- package/src/acvm/oracle/oracle.ts +2 -32
- package/src/acvm/oracle/typed_oracle.ts +3 -20
- package/src/acvm/serialize.ts +1 -1
- package/src/avm/avm_context.ts +2 -3
- package/src/avm/avm_execution_environment.ts +6 -31
- package/src/avm/avm_memory_types.ts +6 -6
- package/src/avm/avm_simulator.ts +28 -23
- package/src/avm/avm_tree.ts +67 -53
- package/src/avm/errors.ts +12 -14
- package/src/avm/fixtures/index.ts +2 -3
- package/src/avm/journal/journal.ts +206 -68
- package/src/avm/opcodes/environment_getters.ts +1 -4
- package/src/avm/opcodes/external_calls.ts +3 -19
- package/src/avm/opcodes/misc.ts +2 -2
- package/src/client/client_execution_context.ts +22 -68
- package/src/client/db_oracle.ts +2 -2
- package/src/client/execution_note_cache.ts +13 -3
- package/src/client/private_execution.ts +3 -7
- package/src/client/simulator.ts +4 -4
- package/src/client/unconstrained_execution.ts +2 -2
- package/src/client/view_data_oracle.ts +5 -6
- package/src/common/debug_fn_name.ts +7 -13
- package/src/providers/acvm_native.ts +3 -3
- package/src/providers/factory.ts +3 -3
- package/src/public/enqueued_call_side_effect_trace.ts +68 -90
- package/src/public/executor_metrics.ts +0 -4
- package/src/public/fixtures/index.ts +28 -17
- package/src/public/index.ts +0 -1
- package/src/public/public_db_sources.ts +32 -19
- package/src/public/public_processor.ts +52 -55
- package/src/public/public_processor_metrics.ts +1 -1
- package/src/public/public_tx_context.ts +89 -76
- package/src/public/public_tx_simulator.ts +58 -49
- package/src/public/side_effect_trace_interface.ts +8 -15
- package/src/public/transitional_adapters.ts +43 -215
- package/dest/public/dual_side_effect_trace.d.ts +0 -77
- package/dest/public/dual_side_effect_trace.d.ts.map +0 -1
- package/dest/public/dual_side_effect_trace.js +0 -119
- package/dest/public/side_effect_trace.d.ts +0 -96
- package/dest/public/side_effect_trace.d.ts.map +0 -1
- package/dest/public/side_effect_trace.js +0 -309
- package/src/public/dual_side_effect_trace.ts +0 -242
- package/src/public/side_effect_trace.ts +0 -536
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { MerkleTreeId } from '@aztec/circuit-types';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
AztecAddress,
|
|
4
|
+
CANONICAL_AUTH_REGISTRY_ADDRESS,
|
|
5
|
+
DEPLOYER_CONTRACT_ADDRESS,
|
|
6
|
+
FEE_JUICE_ADDRESS,
|
|
7
|
+
MULTI_CALL_ENTRYPOINT_ADDRESS,
|
|
8
|
+
NullifierLeafPreimage,
|
|
6
9
|
type PublicCallRequest,
|
|
7
10
|
type PublicDataTreeLeafPreimage,
|
|
11
|
+
REGISTERER_CONTRACT_ADDRESS,
|
|
12
|
+
ROUTER_ADDRESS,
|
|
8
13
|
SerializableContractInstance,
|
|
9
14
|
} from '@aztec/circuits.js';
|
|
10
15
|
import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
|
|
11
16
|
import { Fr } from '@aztec/foundation/fields';
|
|
12
17
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
13
|
-
import {
|
|
18
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
14
19
|
|
|
15
20
|
import { strict as assert } from 'assert';
|
|
16
21
|
|
|
17
22
|
import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
|
|
18
23
|
import { type WorldStateDB } from '../../public/public_db_sources.js';
|
|
19
24
|
import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
|
|
20
|
-
import { type AvmContractCallResult } from '../avm_contract_call_result.js';
|
|
21
25
|
import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
22
26
|
import { AvmEphemeralForest } from '../avm_tree.js';
|
|
23
27
|
import { NullifierCollisionError, NullifierManager } from './nullifiers.js';
|
|
@@ -33,7 +37,7 @@ import { PublicStorage } from './public_storage.js';
|
|
|
33
37
|
* Manages merging of successful/reverted child state into current state.
|
|
34
38
|
*/
|
|
35
39
|
export class AvmPersistableStateManager {
|
|
36
|
-
private readonly log =
|
|
40
|
+
private readonly log = createLogger('simulator:avm:state_manager');
|
|
37
41
|
|
|
38
42
|
/** Make sure a forked state is never merged twice. */
|
|
39
43
|
private alreadyMergedIntoParent = false;
|
|
@@ -148,14 +152,16 @@ export class AvmPersistableStateManager {
|
|
|
148
152
|
* @param slot - the slot in the contract's storage being written to
|
|
149
153
|
* @param value - the value being written to the slot
|
|
150
154
|
*/
|
|
151
|
-
public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr): Promise<void> {
|
|
155
|
+
public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr, protocolWrite = false): Promise<void> {
|
|
152
156
|
this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
|
|
157
|
+
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
158
|
+
this.log.debug(`leafSlot=${leafSlot}`);
|
|
153
159
|
// Cache storage writes for later reference/reads
|
|
154
160
|
this.publicStorage.write(contractAddress, slot, value);
|
|
155
|
-
|
|
161
|
+
|
|
156
162
|
if (this.doMerkleOperations) {
|
|
157
163
|
const result = await this.merkleTrees.writePublicStorage(leafSlot, value);
|
|
158
|
-
assert(result !== undefined, 'Public data tree insertion error. You might want to disable
|
|
164
|
+
assert(result !== undefined, 'Public data tree insertion error. You might want to disable doMerkleOperations.');
|
|
159
165
|
this.log.debug(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`);
|
|
160
166
|
|
|
161
167
|
const lowLeafInfo = result.lowWitness;
|
|
@@ -163,13 +169,21 @@ export class AvmPersistableStateManager {
|
|
|
163
169
|
const lowLeafIndex = lowLeafInfo.index;
|
|
164
170
|
const lowLeafPath = lowLeafInfo.siblingPath;
|
|
165
171
|
|
|
166
|
-
const
|
|
167
|
-
|
|
172
|
+
const newLeafPreimage = result.element as PublicDataTreeLeafPreimage;
|
|
173
|
+
let insertionPath: Fr[] | undefined;
|
|
174
|
+
if (!result.update) {
|
|
175
|
+
insertionPath = result.insertionPath;
|
|
176
|
+
assert(
|
|
177
|
+
newLeafPreimage.value.equals(value),
|
|
178
|
+
`Value mismatch when performing public data write (got value: ${value}, value in ephemeral tree: ${newLeafPreimage.value})`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
168
181
|
|
|
169
182
|
this.trace.tracePublicStorageWrite(
|
|
170
183
|
contractAddress,
|
|
171
184
|
slot,
|
|
172
185
|
value,
|
|
186
|
+
protocolWrite,
|
|
173
187
|
lowLeafPreimage,
|
|
174
188
|
new Fr(lowLeafIndex),
|
|
175
189
|
lowLeafPath,
|
|
@@ -177,7 +191,7 @@ export class AvmPersistableStateManager {
|
|
|
177
191
|
insertionPath,
|
|
178
192
|
);
|
|
179
193
|
} else {
|
|
180
|
-
this.trace.tracePublicStorageWrite(contractAddress, slot, value);
|
|
194
|
+
this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
|
|
181
195
|
}
|
|
182
196
|
}
|
|
183
197
|
|
|
@@ -191,8 +205,8 @@ export class AvmPersistableStateManager {
|
|
|
191
205
|
public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
192
206
|
const { value, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
193
207
|
this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`);
|
|
194
|
-
|
|
195
208
|
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
209
|
+
this.log.debug(`leafSlot=${leafSlot}`);
|
|
196
210
|
|
|
197
211
|
if (this.doMerkleOperations) {
|
|
198
212
|
// Get leaf if present, low leaf if absent
|
|
@@ -200,19 +214,25 @@ export class AvmPersistableStateManager {
|
|
|
200
214
|
const {
|
|
201
215
|
preimage,
|
|
202
216
|
index: leafIndex,
|
|
203
|
-
|
|
217
|
+
alreadyPresent,
|
|
204
218
|
} = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
|
|
205
219
|
// The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag)
|
|
206
220
|
// In either case, we just want the sibling path to this leaf - it's up to the avm to distinguish if it's a low leaf or not
|
|
207
221
|
const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
|
|
208
222
|
const leafPreimage = preimage as PublicDataTreeLeafPreimage;
|
|
209
223
|
|
|
224
|
+
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
210
225
|
this.log.debug(
|
|
211
226
|
`leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`,
|
|
212
227
|
);
|
|
213
|
-
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
214
228
|
|
|
215
|
-
if (
|
|
229
|
+
if (alreadyPresent) {
|
|
230
|
+
assert(
|
|
231
|
+
leafPreimage.value.equals(value),
|
|
232
|
+
`Value mismatch when performing public data read (got value: ${value}, value in ephemeral tree: ${leafPreimage.value})`,
|
|
233
|
+
);
|
|
234
|
+
} else {
|
|
235
|
+
this.log.debug(`Slot has never been written before!`);
|
|
216
236
|
// Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
|
|
217
237
|
assert(
|
|
218
238
|
leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
|
|
@@ -220,9 +240,6 @@ export class AvmPersistableStateManager {
|
|
|
220
240
|
'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist or is the max value.',
|
|
221
241
|
);
|
|
222
242
|
}
|
|
223
|
-
this.log.debug(
|
|
224
|
-
`Tracing storage leaf preimage slot=${slot}, leafSlot=${leafSlot}, value=${value}, nextKey=${leafPreimage.nextSlot}, nextIndex=${leafPreimage.nextIndex}`,
|
|
225
|
-
);
|
|
226
243
|
// On non-existence, AVM circuit will need to recognize that leafPreimage.slot != leafSlot,
|
|
227
244
|
// prove that this is a low leaf that skips leafSlot, and then prove membership of the leaf.
|
|
228
245
|
this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, new Fr(leafIndex), leafPath);
|
|
@@ -299,8 +316,47 @@ export class AvmPersistableStateManager {
|
|
|
299
316
|
public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise<boolean> {
|
|
300
317
|
this.log.debug(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`);
|
|
301
318
|
const siloedNullifier = siloNullifier(contractAddress, nullifier);
|
|
319
|
+
const [exists, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
|
|
320
|
+
siloedNullifier,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
if (this.doMerkleOperations) {
|
|
324
|
+
this.trace.traceNullifierCheck(
|
|
325
|
+
siloedNullifier,
|
|
326
|
+
exists,
|
|
327
|
+
leafOrLowLeafPreimage,
|
|
328
|
+
leafOrLowLeafIndex,
|
|
329
|
+
leafOrLowLeafPath,
|
|
330
|
+
);
|
|
331
|
+
} else {
|
|
332
|
+
this.trace.traceNullifierCheck(siloedNullifier, exists);
|
|
333
|
+
}
|
|
334
|
+
return Promise.resolve(exists);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Helper to get membership information for a siloed nullifier when checking its existence.
|
|
339
|
+
* Optionally trace the nullifier check.
|
|
340
|
+
*
|
|
341
|
+
* @param siloedNullifier - the siloed nullifier to get membership information for
|
|
342
|
+
* @returns
|
|
343
|
+
* - exists - whether the nullifier exists in the nullifier set
|
|
344
|
+
* - leafOrLowLeafPreimage - the preimage of the nullifier leaf or its low-leaf if it doesn't exist
|
|
345
|
+
* - leafOrLowLeafIndex - the leaf index of the nullifier leaf or its low-leaf if it doesn't exist
|
|
346
|
+
* - leafOrLowLeafPath - the sibling path of the nullifier leaf or its low-leaf if it doesn't exist
|
|
347
|
+
*/
|
|
348
|
+
private async getNullifierMembership(
|
|
349
|
+
siloedNullifier: Fr,
|
|
350
|
+
): Promise<
|
|
351
|
+
[
|
|
352
|
+
/*exists=*/ boolean,
|
|
353
|
+
/*leafOrLowLeafPreimage=*/ NullifierLeafPreimage,
|
|
354
|
+
/*leafOrLowLeafIndex=*/ Fr,
|
|
355
|
+
/*leafOrLowLeafIndexPath=*/ Fr[],
|
|
356
|
+
]
|
|
357
|
+
> {
|
|
302
358
|
const [exists, isPending, _] = await this.nullifiers.checkExists(siloedNullifier);
|
|
303
|
-
this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}, pending=${isPending}
|
|
359
|
+
this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), pending=${isPending}`);
|
|
304
360
|
|
|
305
361
|
if (this.doMerkleOperations) {
|
|
306
362
|
// Get leaf if present, low leaf if absent
|
|
@@ -308,29 +364,30 @@ export class AvmPersistableStateManager {
|
|
|
308
364
|
const {
|
|
309
365
|
preimage,
|
|
310
366
|
index: leafIndex,
|
|
311
|
-
|
|
367
|
+
alreadyPresent,
|
|
312
368
|
} = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.NULLIFIER_TREE, siloedNullifier);
|
|
313
369
|
const leafPreimage = preimage as NullifierLeafPreimage;
|
|
314
370
|
const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
|
|
315
371
|
|
|
316
|
-
assert(
|
|
372
|
+
assert(
|
|
373
|
+
alreadyPresent == exists,
|
|
374
|
+
'WorldStateDB contains nullifier leaf, but merkle tree does not (or vice versa).... This is a bug!',
|
|
375
|
+
);
|
|
317
376
|
|
|
318
377
|
if (exists) {
|
|
319
378
|
this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`);
|
|
320
379
|
} else {
|
|
321
380
|
// Sanity check that the leaf value is skipped by low leaf when it doesn't exist
|
|
322
381
|
assert(
|
|
323
|
-
|
|
324
|
-
|
|
382
|
+
leafPreimage.nullifier.toBigInt() < siloedNullifier.toBigInt() &&
|
|
383
|
+
(leafPreimage.nextIndex === 0n || leafPreimage.nextNullifier.toBigInt() > siloedNullifier.toBigInt()),
|
|
325
384
|
'Nullifier tree low leaf should skip the target leaf nullifier when the target leaf does not exist.',
|
|
326
385
|
);
|
|
327
386
|
}
|
|
328
|
-
|
|
329
|
-
this.trace.traceNullifierCheck(siloedNullifier, exists, leafPreimage, new Fr(leafIndex), leafPath);
|
|
387
|
+
return [exists, leafPreimage, new Fr(leafIndex), leafPath];
|
|
330
388
|
} else {
|
|
331
|
-
|
|
389
|
+
return [exists, NullifierLeafPreimage.empty(), Fr.ZERO, []];
|
|
332
390
|
}
|
|
333
|
-
return Promise.resolve(exists);
|
|
334
391
|
}
|
|
335
392
|
|
|
336
393
|
/**
|
|
@@ -355,11 +412,11 @@ export class AvmPersistableStateManager {
|
|
|
355
412
|
// Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert
|
|
356
413
|
// It might be better to catch the error from the insert operation
|
|
357
414
|
// Trace all nullifier creations, even duplicate insertions that fail
|
|
358
|
-
const { preimage, index,
|
|
415
|
+
const { preimage, index, alreadyPresent } = await this.merkleTrees.getLeafOrLowLeafInfo(
|
|
359
416
|
MerkleTreeId.NULLIFIER_TREE,
|
|
360
417
|
siloedNullifier,
|
|
361
418
|
);
|
|
362
|
-
if (
|
|
419
|
+
if (alreadyPresent) {
|
|
363
420
|
this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`);
|
|
364
421
|
// If the nullifier is already present, we should not insert it again
|
|
365
422
|
// instead we provide the direct membership path
|
|
@@ -367,7 +424,7 @@ export class AvmPersistableStateManager {
|
|
|
367
424
|
// This just becomes a nullifier read hint
|
|
368
425
|
this.trace.traceNullifierCheck(
|
|
369
426
|
siloedNullifier,
|
|
370
|
-
/*exists=*/
|
|
427
|
+
/*exists=*/ alreadyPresent,
|
|
371
428
|
preimage as NullifierLeafPreimage,
|
|
372
429
|
new Fr(index),
|
|
373
430
|
path,
|
|
@@ -379,6 +436,11 @@ export class AvmPersistableStateManager {
|
|
|
379
436
|
// Cache pending nullifiers for later access
|
|
380
437
|
await this.nullifiers.append(siloedNullifier);
|
|
381
438
|
// We append the new nullifier
|
|
439
|
+
this.log.debug(
|
|
440
|
+
`Nullifier tree root before insertion ${this.merkleTrees.treeMap
|
|
441
|
+
.get(MerkleTreeId.NULLIFIER_TREE)!
|
|
442
|
+
.getRoot()}`,
|
|
443
|
+
);
|
|
382
444
|
const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier);
|
|
383
445
|
this.log.debug(
|
|
384
446
|
`Nullifier tree root after insertion ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
|
|
@@ -472,18 +534,59 @@ export class AvmPersistableStateManager {
|
|
|
472
534
|
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
473
535
|
const exists = instanceWithAddress !== undefined;
|
|
474
536
|
|
|
475
|
-
|
|
537
|
+
let [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = [
|
|
538
|
+
exists,
|
|
539
|
+
NullifierLeafPreimage.empty(),
|
|
540
|
+
Fr.ZERO,
|
|
541
|
+
new Array<Fr>(),
|
|
542
|
+
];
|
|
543
|
+
if (!contractAddressIsCanonical(contractAddress)) {
|
|
544
|
+
const contractAddressNullifier = siloNullifier(
|
|
545
|
+
AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
|
|
546
|
+
contractAddress.toField(),
|
|
547
|
+
);
|
|
548
|
+
[existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
|
|
549
|
+
/*siloedNullifier=*/ contractAddressNullifier,
|
|
550
|
+
);
|
|
551
|
+
assert(
|
|
552
|
+
exists == existsInTree,
|
|
553
|
+
'WorldStateDB contains contract instance, but nullifier tree does not contain contract address (or vice versa).... This is a bug!',
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
476
557
|
if (exists) {
|
|
477
558
|
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
478
559
|
this.log.debug(
|
|
479
560
|
`Got contract instance (address=${contractAddress}): exists=${exists}, instance=${jsonStringify(instance)}`,
|
|
480
561
|
);
|
|
481
|
-
this.
|
|
562
|
+
if (this.doMerkleOperations) {
|
|
563
|
+
this.trace.traceGetContractInstance(
|
|
564
|
+
contractAddress,
|
|
565
|
+
exists,
|
|
566
|
+
instance,
|
|
567
|
+
leafOrLowLeafPreimage,
|
|
568
|
+
leafOrLowLeafIndex,
|
|
569
|
+
leafOrLowLeafPath,
|
|
570
|
+
);
|
|
571
|
+
} else {
|
|
572
|
+
this.trace.traceGetContractInstance(contractAddress, exists, instance);
|
|
573
|
+
}
|
|
482
574
|
|
|
483
575
|
return Promise.resolve(instance);
|
|
484
576
|
} else {
|
|
485
577
|
this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
|
|
486
|
-
this.
|
|
578
|
+
if (this.doMerkleOperations) {
|
|
579
|
+
this.trace.traceGetContractInstance(
|
|
580
|
+
contractAddress,
|
|
581
|
+
exists,
|
|
582
|
+
/*instance=*/ undefined,
|
|
583
|
+
leafOrLowLeafPreimage,
|
|
584
|
+
leafOrLowLeafIndex,
|
|
585
|
+
leafOrLowLeafPath,
|
|
586
|
+
);
|
|
587
|
+
} else {
|
|
588
|
+
this.trace.traceGetContractInstance(contractAddress, exists);
|
|
589
|
+
}
|
|
487
590
|
return Promise.resolve(undefined);
|
|
488
591
|
}
|
|
489
592
|
}
|
|
@@ -496,6 +599,26 @@ export class AvmPersistableStateManager {
|
|
|
496
599
|
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
497
600
|
const exists = instanceWithAddress !== undefined;
|
|
498
601
|
|
|
602
|
+
let [existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = [
|
|
603
|
+
exists,
|
|
604
|
+
NullifierLeafPreimage.empty(),
|
|
605
|
+
Fr.ZERO,
|
|
606
|
+
new Array<Fr>(),
|
|
607
|
+
];
|
|
608
|
+
if (!contractAddressIsCanonical(contractAddress)) {
|
|
609
|
+
const contractAddressNullifier = siloNullifier(
|
|
610
|
+
AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
|
|
611
|
+
contractAddress.toField(),
|
|
612
|
+
);
|
|
613
|
+
[existsInTree, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
|
|
614
|
+
/*siloedNullifier=*/ contractAddressNullifier,
|
|
615
|
+
);
|
|
616
|
+
assert(
|
|
617
|
+
exists == existsInTree,
|
|
618
|
+
'WorldStateDB contains contract instance, but nullifier tree does not contain contract address (or vice versa).... This is a bug!',
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
|
|
499
622
|
if (exists) {
|
|
500
623
|
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
501
624
|
const contractClass = await this.worldStateDB.getContractClass(instance.contractClassId);
|
|
@@ -517,51 +640,66 @@ export class AvmPersistableStateManager {
|
|
|
517
640
|
publicBytecodeCommitment: bytecodeCommitment,
|
|
518
641
|
};
|
|
519
642
|
|
|
520
|
-
this.
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
643
|
+
if (this.doMerkleOperations) {
|
|
644
|
+
this.trace.traceGetBytecode(
|
|
645
|
+
contractAddress,
|
|
646
|
+
exists,
|
|
647
|
+
contractClass.packedBytecode,
|
|
648
|
+
instance,
|
|
649
|
+
contractClassPreimage,
|
|
650
|
+
leafOrLowLeafPreimage,
|
|
651
|
+
leafOrLowLeafIndex,
|
|
652
|
+
leafOrLowLeafPath,
|
|
653
|
+
);
|
|
654
|
+
} else {
|
|
655
|
+
this.trace.traceGetBytecode(
|
|
656
|
+
contractAddress,
|
|
657
|
+
exists,
|
|
658
|
+
contractClass.packedBytecode,
|
|
659
|
+
instance,
|
|
660
|
+
contractClassPreimage,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
527
663
|
|
|
528
664
|
return contractClass.packedBytecode;
|
|
529
665
|
} else {
|
|
530
666
|
// If the contract instance is not found, we assume it has not been deployed.
|
|
531
667
|
// It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
|
|
532
668
|
// This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
|
|
533
|
-
this.
|
|
669
|
+
if (this.doMerkleOperations) {
|
|
670
|
+
this.trace.traceGetBytecode(
|
|
671
|
+
contractAddress,
|
|
672
|
+
exists,
|
|
673
|
+
/*instance=*/ undefined,
|
|
674
|
+
/*contractClass=*/ undefined,
|
|
675
|
+
/*bytecode=*/ undefined,
|
|
676
|
+
leafOrLowLeafPreimage,
|
|
677
|
+
leafOrLowLeafIndex,
|
|
678
|
+
leafOrLowLeafPath,
|
|
679
|
+
);
|
|
680
|
+
} else {
|
|
681
|
+
this.trace.traceGetBytecode(contractAddress, exists); // bytecode, instance, class undefined
|
|
682
|
+
}
|
|
534
683
|
return undefined;
|
|
535
684
|
}
|
|
536
685
|
}
|
|
537
686
|
|
|
538
|
-
public async traceNestedCall(
|
|
539
|
-
forkedState: AvmPersistableStateManager,
|
|
540
|
-
nestedEnvironment: AvmExecutionEnvironment,
|
|
541
|
-
startGasLeft: Gas,
|
|
542
|
-
bytecode: Buffer,
|
|
543
|
-
avmCallResults: AvmContractCallResult,
|
|
544
|
-
) {
|
|
545
|
-
const functionName = await getPublicFunctionDebugName(
|
|
546
|
-
this.worldStateDB,
|
|
547
|
-
nestedEnvironment.address,
|
|
548
|
-
nestedEnvironment.functionSelector,
|
|
549
|
-
nestedEnvironment.calldata,
|
|
550
|
-
);
|
|
551
|
-
|
|
552
|
-
this.log.verbose(`[AVM] Tracing nested external contract call ${functionName}`);
|
|
553
|
-
|
|
554
|
-
this.trace.traceNestedCall(
|
|
555
|
-
forkedState.trace,
|
|
556
|
-
nestedEnvironment,
|
|
557
|
-
startGasLeft,
|
|
558
|
-
bytecode,
|
|
559
|
-
avmCallResults,
|
|
560
|
-
functionName,
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
687
|
public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
|
|
565
688
|
this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
|
|
566
689
|
}
|
|
690
|
+
|
|
691
|
+
public async getPublicFunctionDebugName(avmEnvironment: AvmExecutionEnvironment): Promise<string> {
|
|
692
|
+
return await getPublicFunctionDebugName(this.worldStateDB, avmEnvironment.address, avmEnvironment.calldata);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function contractAddressIsCanonical(contractAddress: AztecAddress): boolean {
|
|
697
|
+
return (
|
|
698
|
+
contractAddress.equals(AztecAddress.fromNumber(CANONICAL_AUTH_REGISTRY_ADDRESS)) ||
|
|
699
|
+
contractAddress.equals(AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS)) ||
|
|
700
|
+
contractAddress.equals(AztecAddress.fromNumber(REGISTERER_CONTRACT_ADDRESS)) ||
|
|
701
|
+
contractAddress.equals(AztecAddress.fromNumber(MULTI_CALL_ENTRYPOINT_ADDRESS)) ||
|
|
702
|
+
contractAddress.equals(AztecAddress.fromNumber(FEE_JUICE_ADDRESS)) ||
|
|
703
|
+
contractAddress.equals(AztecAddress.fromNumber(ROUTER_ADDRESS))
|
|
704
|
+
);
|
|
567
705
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
|
-
import { Field,
|
|
2
|
+
import { Field, Uint64 } from '../avm_memory_types.js';
|
|
3
3
|
import { InstructionExecutionError } from '../errors.js';
|
|
4
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
5
5
|
import { Addressing } from './addressing_mode.js';
|
|
@@ -8,7 +8,6 @@ import { Instruction } from './instruction.js';
|
|
|
8
8
|
export enum EnvironmentVariable {
|
|
9
9
|
ADDRESS,
|
|
10
10
|
SENDER,
|
|
11
|
-
FUNCTIONSELECTOR,
|
|
12
11
|
TRANSACTIONFEE,
|
|
13
12
|
CHAINID,
|
|
14
13
|
VERSION,
|
|
@@ -27,8 +26,6 @@ function getValue(e: EnvironmentVariable, ctx: AvmContext) {
|
|
|
27
26
|
return new Field(ctx.environment.address.toField());
|
|
28
27
|
case EnvironmentVariable.SENDER:
|
|
29
28
|
return new Field(ctx.environment.sender.toField());
|
|
30
|
-
case EnvironmentVariable.FUNCTIONSELECTOR:
|
|
31
|
-
return new Uint32(ctx.environment.functionSelector.value);
|
|
32
29
|
case EnvironmentVariable.TRANSACTIONFEE:
|
|
33
30
|
return new Field(ctx.environment.transactionFee);
|
|
34
31
|
case EnvironmentVariable.CHAINID:
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Fr, FunctionSelector, Gas, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js';
|
|
2
|
-
|
|
3
1
|
import type { AvmContext } from '../avm_context.js';
|
|
4
2
|
import { type AvmContractCallResult } from '../avm_contract_call_result.js';
|
|
5
3
|
import { type Field, TypeTag, Uint1 } from '../avm_memory_types.js';
|
|
@@ -45,7 +43,6 @@ abstract class ExternalCall extends Instruction {
|
|
|
45
43
|
|
|
46
44
|
const callAddress = memory.getAs<Field>(addrOffset);
|
|
47
45
|
const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
|
|
48
|
-
const functionSelector = new Fr(PUBLIC_DISPATCH_SELECTOR);
|
|
49
46
|
// If we are already in a static call, we propagate the environment.
|
|
50
47
|
const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type;
|
|
51
48
|
|
|
@@ -62,15 +59,10 @@ abstract class ExternalCall extends Instruction {
|
|
|
62
59
|
const allocatedGas = { l2Gas: allocatedL2Gas, daGas: allocatedDaGas };
|
|
63
60
|
context.machineState.consumeGas(allocatedGas);
|
|
64
61
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
calldata,
|
|
68
|
-
allocatedGas,
|
|
69
|
-
callType,
|
|
70
|
-
FunctionSelector.fromField(functionSelector),
|
|
71
|
-
);
|
|
62
|
+
const aztecAddress = callAddress.toAztecAddress();
|
|
63
|
+
const nestedContext = context.createNestedContractCallContext(aztecAddress, calldata, allocatedGas, callType);
|
|
72
64
|
|
|
73
|
-
const simulator =
|
|
65
|
+
const simulator = await AvmSimulator.build(nestedContext);
|
|
74
66
|
const nestedCallResults: AvmContractCallResult = await simulator.execute();
|
|
75
67
|
const success = !nestedCallResults.reverted;
|
|
76
68
|
|
|
@@ -102,14 +94,6 @@ abstract class ExternalCall extends Instruction {
|
|
|
102
94
|
} else {
|
|
103
95
|
context.persistableState.reject(nestedContext.persistableState);
|
|
104
96
|
}
|
|
105
|
-
await context.persistableState.traceNestedCall(
|
|
106
|
-
/*nestedState=*/ nestedContext.persistableState,
|
|
107
|
-
/*nestedEnvironment=*/ nestedContext.environment,
|
|
108
|
-
/*startGasLeft=*/ Gas.from(allocatedGas),
|
|
109
|
-
/*bytecode=*/ simulator.getBytecode()!,
|
|
110
|
-
/*avmCallResults=*/ nestedCallResults,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
97
|
memory.assert({ reads: calldataSize + 4, writes: 1, addressing });
|
|
114
98
|
}
|
|
115
99
|
|
package/src/avm/opcodes/misc.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyStringFormatting,
|
|
1
|
+
import { applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
2
2
|
|
|
3
3
|
import { type AvmContext } from '../avm_context.js';
|
|
4
4
|
import { TypeTag } from '../avm_memory_types.js';
|
|
@@ -9,7 +9,7 @@ import { Instruction } from './instruction.js';
|
|
|
9
9
|
export class DebugLog extends Instruction {
|
|
10
10
|
static type: string = 'DEBUGLOG';
|
|
11
11
|
static readonly opcode: Opcode = Opcode.DEBUGLOG;
|
|
12
|
-
static readonly logger =
|
|
12
|
+
static readonly logger = createLogger('simulator:avm:debug_log');
|
|
13
13
|
|
|
14
14
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
15
15
|
static readonly wireFormat: OperandType[] = [
|