@aztec/simulator 0.66.0 → 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 -1
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +3 -3
- package/dest/acvm/oracle/typed_oracle.d.ts +2 -2
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +3 -3
- 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 +3 -3
- 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 +22 -13
- 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 +108 -29
- 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 +3 -3
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +14 -8
- 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 +4 -4
- 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 +37 -58
- 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 +24 -1
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +15 -9
- 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 +4 -4
- 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 +30 -22
- package/dest/public/public_tx_context.d.ts +13 -10
- package/dest/public/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_context.js +46 -31
- 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 -23
- 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 -2
- package/dest/public/transitional_adapters.d.ts.map +1 -1
- package/dest/public/transitional_adapters.js +28 -24
- package/package.json +16 -9
- package/src/acvm/acvm.ts +2 -2
- package/src/acvm/oracle/oracle.ts +2 -2
- package/src/acvm/oracle/typed_oracle.ts +3 -3
- 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 +2 -2
- package/src/avm/avm_simulator.ts +24 -20
- package/src/avm/errors.ts +12 -14
- package/src/avm/fixtures/index.ts +2 -3
- package/src/avm/journal/journal.ts +189 -63
- package/src/avm/opcodes/external_calls.ts +3 -19
- package/src/avm/opcodes/misc.ts +2 -2
- package/src/client/client_execution_context.ts +17 -9
- package/src/client/db_oracle.ts +2 -2
- package/src/client/execution_note_cache.ts +13 -3
- package/src/client/private_execution.ts +3 -3
- 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 +54 -74
- package/src/public/executor_metrics.ts +0 -4
- package/src/public/fixtures/index.ts +23 -10
- package/src/public/index.ts +0 -1
- package/src/public/public_db_sources.ts +3 -3
- package/src/public/public_processor.ts +46 -47
- package/src/public/public_tx_context.ts +52 -32
- package/src/public/public_tx_simulator.ts +58 -38
- package/src/public/side_effect_trace_interface.ts +8 -15
- package/src/public/transitional_adapters.ts +39 -24
- 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;
|
|
@@ -164,16 +170,20 @@ export class AvmPersistableStateManager {
|
|
|
164
170
|
const lowLeafPath = lowLeafInfo.siblingPath;
|
|
165
171
|
|
|
166
172
|
const newLeafPreimage = result.element as PublicDataTreeLeafPreimage;
|
|
167
|
-
let insertionPath;
|
|
168
|
-
|
|
173
|
+
let insertionPath: Fr[] | undefined;
|
|
169
174
|
if (!result.update) {
|
|
170
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
|
+
);
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
this.trace.tracePublicStorageWrite(
|
|
174
183
|
contractAddress,
|
|
175
184
|
slot,
|
|
176
185
|
value,
|
|
186
|
+
protocolWrite,
|
|
177
187
|
lowLeafPreimage,
|
|
178
188
|
new Fr(lowLeafIndex),
|
|
179
189
|
lowLeafPath,
|
|
@@ -181,7 +191,7 @@ export class AvmPersistableStateManager {
|
|
|
181
191
|
insertionPath,
|
|
182
192
|
);
|
|
183
193
|
} else {
|
|
184
|
-
this.trace.tracePublicStorageWrite(contractAddress, slot, value);
|
|
194
|
+
this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
|
|
185
195
|
}
|
|
186
196
|
}
|
|
187
197
|
|
|
@@ -195,8 +205,8 @@ export class AvmPersistableStateManager {
|
|
|
195
205
|
public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
196
206
|
const { value, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
197
207
|
this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`);
|
|
198
|
-
|
|
199
208
|
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
209
|
+
this.log.debug(`leafSlot=${leafSlot}`);
|
|
200
210
|
|
|
201
211
|
if (this.doMerkleOperations) {
|
|
202
212
|
// Get leaf if present, low leaf if absent
|
|
@@ -211,12 +221,18 @@ export class AvmPersistableStateManager {
|
|
|
211
221
|
const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
|
|
212
222
|
const leafPreimage = preimage as PublicDataTreeLeafPreimage;
|
|
213
223
|
|
|
224
|
+
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
214
225
|
this.log.debug(
|
|
215
226
|
`leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`,
|
|
216
227
|
);
|
|
217
|
-
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
218
228
|
|
|
219
|
-
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!`);
|
|
220
236
|
// Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
|
|
221
237
|
assert(
|
|
222
238
|
leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
|
|
@@ -224,9 +240,6 @@ export class AvmPersistableStateManager {
|
|
|
224
240
|
'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist or is the max value.',
|
|
225
241
|
);
|
|
226
242
|
}
|
|
227
|
-
this.log.debug(
|
|
228
|
-
`Tracing storage leaf preimage slot=${slot}, leafSlot=${leafSlot}, value=${value}, nextKey=${leafPreimage.nextSlot}, nextIndex=${leafPreimage.nextIndex}`,
|
|
229
|
-
);
|
|
230
243
|
// On non-existence, AVM circuit will need to recognize that leafPreimage.slot != leafSlot,
|
|
231
244
|
// prove that this is a low leaf that skips leafSlot, and then prove membership of the leaf.
|
|
232
245
|
this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, new Fr(leafIndex), leafPath);
|
|
@@ -303,8 +316,47 @@ export class AvmPersistableStateManager {
|
|
|
303
316
|
public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise<boolean> {
|
|
304
317
|
this.log.debug(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`);
|
|
305
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
|
+
> {
|
|
306
358
|
const [exists, isPending, _] = await this.nullifiers.checkExists(siloedNullifier);
|
|
307
|
-
this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}, pending=${isPending}
|
|
359
|
+
this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), pending=${isPending}`);
|
|
308
360
|
|
|
309
361
|
if (this.doMerkleOperations) {
|
|
310
362
|
// Get leaf if present, low leaf if absent
|
|
@@ -319,7 +371,7 @@ export class AvmPersistableStateManager {
|
|
|
319
371
|
|
|
320
372
|
assert(
|
|
321
373
|
alreadyPresent == exists,
|
|
322
|
-
'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!',
|
|
374
|
+
'WorldStateDB contains nullifier leaf, but merkle tree does not (or vice versa).... This is a bug!',
|
|
323
375
|
);
|
|
324
376
|
|
|
325
377
|
if (exists) {
|
|
@@ -327,17 +379,15 @@ export class AvmPersistableStateManager {
|
|
|
327
379
|
} else {
|
|
328
380
|
// Sanity check that the leaf value is skipped by low leaf when it doesn't exist
|
|
329
381
|
assert(
|
|
330
|
-
|
|
331
|
-
|
|
382
|
+
leafPreimage.nullifier.toBigInt() < siloedNullifier.toBigInt() &&
|
|
383
|
+
(leafPreimage.nextIndex === 0n || leafPreimage.nextNullifier.toBigInt() > siloedNullifier.toBigInt()),
|
|
332
384
|
'Nullifier tree low leaf should skip the target leaf nullifier when the target leaf does not exist.',
|
|
333
385
|
);
|
|
334
386
|
}
|
|
335
|
-
|
|
336
|
-
this.trace.traceNullifierCheck(siloedNullifier, exists, leafPreimage, new Fr(leafIndex), leafPath);
|
|
387
|
+
return [exists, leafPreimage, new Fr(leafIndex), leafPath];
|
|
337
388
|
} else {
|
|
338
|
-
|
|
389
|
+
return [exists, NullifierLeafPreimage.empty(), Fr.ZERO, []];
|
|
339
390
|
}
|
|
340
|
-
return Promise.resolve(exists);
|
|
341
391
|
}
|
|
342
392
|
|
|
343
393
|
/**
|
|
@@ -484,18 +534,59 @@ export class AvmPersistableStateManager {
|
|
|
484
534
|
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
485
535
|
const exists = instanceWithAddress !== undefined;
|
|
486
536
|
|
|
487
|
-
|
|
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
|
+
|
|
488
557
|
if (exists) {
|
|
489
558
|
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
490
559
|
this.log.debug(
|
|
491
560
|
`Got contract instance (address=${contractAddress}): exists=${exists}, instance=${jsonStringify(instance)}`,
|
|
492
561
|
);
|
|
493
|
-
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
|
+
}
|
|
494
574
|
|
|
495
575
|
return Promise.resolve(instance);
|
|
496
576
|
} else {
|
|
497
577
|
this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
|
|
498
|
-
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
|
+
}
|
|
499
590
|
return Promise.resolve(undefined);
|
|
500
591
|
}
|
|
501
592
|
}
|
|
@@ -508,6 +599,26 @@ export class AvmPersistableStateManager {
|
|
|
508
599
|
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
509
600
|
const exists = instanceWithAddress !== undefined;
|
|
510
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
|
+
|
|
511
622
|
if (exists) {
|
|
512
623
|
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
513
624
|
const contractClass = await this.worldStateDB.getContractClass(instance.contractClassId);
|
|
@@ -529,51 +640,66 @@ export class AvmPersistableStateManager {
|
|
|
529
640
|
publicBytecodeCommitment: bytecodeCommitment,
|
|
530
641
|
};
|
|
531
642
|
|
|
532
|
-
this.
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
+
}
|
|
539
663
|
|
|
540
664
|
return contractClass.packedBytecode;
|
|
541
665
|
} else {
|
|
542
666
|
// If the contract instance is not found, we assume it has not been deployed.
|
|
543
667
|
// It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
|
|
544
668
|
// This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
|
|
545
|
-
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
|
+
}
|
|
546
683
|
return undefined;
|
|
547
684
|
}
|
|
548
685
|
}
|
|
549
686
|
|
|
550
|
-
public async traceNestedCall(
|
|
551
|
-
forkedState: AvmPersistableStateManager,
|
|
552
|
-
nestedEnvironment: AvmExecutionEnvironment,
|
|
553
|
-
startGasLeft: Gas,
|
|
554
|
-
bytecode: Buffer,
|
|
555
|
-
avmCallResults: AvmContractCallResult,
|
|
556
|
-
) {
|
|
557
|
-
const functionName = await getPublicFunctionDebugName(
|
|
558
|
-
this.worldStateDB,
|
|
559
|
-
nestedEnvironment.address,
|
|
560
|
-
nestedEnvironment.functionSelector,
|
|
561
|
-
nestedEnvironment.calldata,
|
|
562
|
-
);
|
|
563
|
-
|
|
564
|
-
this.log.verbose(`[AVM] Tracing nested external contract call ${functionName}`);
|
|
565
|
-
|
|
566
|
-
this.trace.traceNestedCall(
|
|
567
|
-
forkedState.trace,
|
|
568
|
-
nestedEnvironment,
|
|
569
|
-
startGasLeft,
|
|
570
|
-
bytecode,
|
|
571
|
-
avmCallResults,
|
|
572
|
-
functionName,
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
687
|
public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
|
|
577
688
|
this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
|
|
578
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
|
+
);
|
|
579
705
|
}
|
|
@@ -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[] = [
|
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
type UnencryptedL2Log,
|
|
12
12
|
} from '@aztec/circuit-types';
|
|
13
13
|
import {
|
|
14
|
+
type BlockHeader,
|
|
14
15
|
CallContext,
|
|
15
16
|
FunctionSelector,
|
|
16
|
-
type Header,
|
|
17
17
|
PRIVATE_CONTEXT_INPUTS_LENGTH,
|
|
18
18
|
PUBLIC_DISPATCH_SELECTOR,
|
|
19
19
|
PrivateContextInputs,
|
|
@@ -23,7 +23,7 @@ import { computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
|
|
|
23
23
|
import { type FunctionAbi, type FunctionArtifact, type NoteSelector, countArgumentsSize } from '@aztec/foundation/abi';
|
|
24
24
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
25
25
|
import { Fr } from '@aztec/foundation/fields';
|
|
26
|
-
import { applyStringFormatting,
|
|
26
|
+
import { applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
27
27
|
|
|
28
28
|
import { type NoteData, toACVMWitness } from '../acvm/index.js';
|
|
29
29
|
import { type PackedValuesCache } from '../common/packed_values_cache.js';
|
|
@@ -66,7 +66,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
66
66
|
private readonly txContext: TxContext,
|
|
67
67
|
private readonly callContext: CallContext,
|
|
68
68
|
/** Header of a block whose state is used during private execution (not the block the transaction is included in). */
|
|
69
|
-
protected readonly historicalHeader:
|
|
69
|
+
protected readonly historicalHeader: BlockHeader,
|
|
70
70
|
/** List of transient auth witnesses to be used during this simulation */
|
|
71
71
|
authWitnesses: AuthWitness[],
|
|
72
72
|
private readonly packedValuesCache: PackedValuesCache,
|
|
@@ -74,7 +74,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
74
74
|
db: DBOracle,
|
|
75
75
|
private node: AztecNode,
|
|
76
76
|
protected sideEffectCounter: number = 0,
|
|
77
|
-
log =
|
|
77
|
+
log = createLogger('simulator:client_execution_context'),
|
|
78
78
|
scopes?: AztecAddress[],
|
|
79
79
|
) {
|
|
80
80
|
super(callContext.contractAddress, authWitnesses, db, node, log, scopes);
|
|
@@ -247,9 +247,10 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
247
247
|
|
|
248
248
|
notes.forEach(n => {
|
|
249
249
|
if (n.index !== undefined) {
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
|
|
250
|
+
const siloedNoteHash = siloNoteHash(n.contractAddress, n.noteHash);
|
|
251
|
+
const uniqueNoteHash = computeUniqueNoteHash(n.nonce, siloedNoteHash);
|
|
252
|
+
|
|
253
|
+
this.noteHashLeafIndexMap.set(uniqueNoteHash.toBigInt(), n.index);
|
|
253
254
|
}
|
|
254
255
|
});
|
|
255
256
|
|
|
@@ -419,7 +420,14 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
419
420
|
const args = this.packedValuesCache.unpack(argsHash);
|
|
420
421
|
|
|
421
422
|
this.log.verbose(
|
|
422
|
-
`Created
|
|
423
|
+
`Created ${callType} public execution request to ${targetArtifact.name}@${targetContractAddress}`,
|
|
424
|
+
{
|
|
425
|
+
sideEffectCounter,
|
|
426
|
+
isStaticCall,
|
|
427
|
+
functionSelector,
|
|
428
|
+
targetContractAddress,
|
|
429
|
+
callType,
|
|
430
|
+
},
|
|
423
431
|
);
|
|
424
432
|
|
|
425
433
|
const request = PublicExecutionRequest.from({
|
|
@@ -537,7 +545,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
537
545
|
}
|
|
538
546
|
|
|
539
547
|
public override debugLog(message: string, fields: Fr[]) {
|
|
540
|
-
this.log.verbose(
|
|
548
|
+
this.log.verbose(`${applyStringFormatting(message, fields)}`, { module: `${this.log.module}:debug_log` });
|
|
541
549
|
}
|
|
542
550
|
|
|
543
551
|
public getDebugFunctionName() {
|
package/src/client/db_oracle.ts
CHANGED
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
type TxScopedL2Log,
|
|
9
9
|
} from '@aztec/circuit-types';
|
|
10
10
|
import {
|
|
11
|
+
type BlockHeader,
|
|
11
12
|
type CompleteAddress,
|
|
12
13
|
type ContractInstance,
|
|
13
|
-
type Header,
|
|
14
14
|
type IndexedTaggingSecret,
|
|
15
15
|
type KeyValidationRequest,
|
|
16
16
|
} from '@aztec/circuits.js';
|
|
@@ -138,7 +138,7 @@ export interface DBOracle extends CommitmentsDB {
|
|
|
138
138
|
*
|
|
139
139
|
* @returns A Promise that resolves to a Header object.
|
|
140
140
|
*/
|
|
141
|
-
|
|
141
|
+
getBlockHeader(): Promise<BlockHeader>;
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* Fetch the index of the leaf in the respective tree
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
|
|
2
2
|
import { type AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
|
-
import {
|
|
3
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
4
4
|
|
|
5
5
|
import { type NoteData } from '../acvm/index.js';
|
|
6
6
|
|
|
@@ -51,11 +51,11 @@ export class ExecutionNoteCache {
|
|
|
51
51
|
// The nonces will be used to create the "complete" nullifier.
|
|
52
52
|
const updatedNotes = this.notes.map(({ note, counter }, i) => {
|
|
53
53
|
const nonce = computeNoteHashNonce(this.txHash, i);
|
|
54
|
-
const uniqueNoteHash = computeUniqueNoteHash(nonce, note.noteHash);
|
|
54
|
+
const uniqueNoteHash = computeUniqueNoteHash(nonce, siloNoteHash(note.contractAddress, note.noteHash));
|
|
55
55
|
return {
|
|
56
56
|
counter,
|
|
57
57
|
note: { ...note, nonce },
|
|
58
|
-
noteHashForConsumption:
|
|
58
|
+
noteHashForConsumption: uniqueNoteHash,
|
|
59
59
|
};
|
|
60
60
|
});
|
|
61
61
|
// Rebuild the data.
|
|
@@ -146,4 +146,14 @@ export class ExecutionNoteCache {
|
|
|
146
146
|
notes.push(note);
|
|
147
147
|
this.noteMap.set(note.note.contractAddress.toBigInt(), notes);
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
getAllNotes(): PendingNote[] {
|
|
151
|
+
return this.notes;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getAllNullifiers(): Fr[] {
|
|
155
|
+
return [...this.nullifierMap.values()].flatMap(nullifierArray =>
|
|
156
|
+
[...nullifierArray.values()].map(val => new Fr(val)),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
149
159
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@aztec/circuits.js';
|
|
9
9
|
import { type FunctionArtifact, type FunctionSelector, countArgumentsSize } from '@aztec/foundation/abi';
|
|
10
10
|
import { type AztecAddress } from '@aztec/foundation/aztec-address';
|
|
11
|
-
import {
|
|
11
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
12
12
|
import { Timer } from '@aztec/foundation/timer';
|
|
13
13
|
|
|
14
14
|
import { fromACVMField, witnessMapToFields } from '../acvm/deserialize.js';
|
|
@@ -24,10 +24,10 @@ export async function executePrivateFunction(
|
|
|
24
24
|
artifact: FunctionArtifact,
|
|
25
25
|
contractAddress: AztecAddress,
|
|
26
26
|
functionSelector: FunctionSelector,
|
|
27
|
-
log =
|
|
27
|
+
log = createLogger('simulator:private_execution'),
|
|
28
28
|
): Promise<PrivateExecutionResult> {
|
|
29
29
|
const functionName = await context.getDebugFunctionName();
|
|
30
|
-
log.verbose(`Executing
|
|
30
|
+
log.verbose(`Executing private function ${functionName}@${contractAddress}`);
|
|
31
31
|
const acir = artifact.bytecode;
|
|
32
32
|
const initialWitness = context.getInitialWitness(artifact);
|
|
33
33
|
const acvmCallback = new Oracle(context);
|
package/src/client/simulator.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from '@aztec/foundation/abi';
|
|
11
11
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
12
12
|
import { Fr } from '@aztec/foundation/fields';
|
|
13
|
-
import { type
|
|
13
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
14
14
|
|
|
15
15
|
import { createSimulationError } from '../common/errors.js';
|
|
16
16
|
import { PackedValuesCache } from '../common/packed_values_cache.js';
|
|
@@ -25,10 +25,10 @@ import { ViewDataOracle } from './view_data_oracle.js';
|
|
|
25
25
|
* The ACIR simulator.
|
|
26
26
|
*/
|
|
27
27
|
export class AcirSimulator {
|
|
28
|
-
private log:
|
|
28
|
+
private log: Logger;
|
|
29
29
|
|
|
30
30
|
constructor(private db: DBOracle, private node: AztecNode) {
|
|
31
|
-
this.log =
|
|
31
|
+
this.log = createLogger('simulator');
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -57,7 +57,7 @@ export class AcirSimulator {
|
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
const header = await this.db.
|
|
60
|
+
const header = await this.db.getBlockHeader();
|
|
61
61
|
|
|
62
62
|
// reserve the first side effect for the tx hash (inserted by the private kernel)
|
|
63
63
|
const startSideEffectCounter = 1;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AbiDecoded, type FunctionArtifact, type FunctionSelector, decodeFromAbi } from '@aztec/foundation/abi';
|
|
2
2
|
import { type AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
3
|
import { type Fr } from '@aztec/foundation/fields';
|
|
4
|
-
import {
|
|
4
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
5
5
|
|
|
6
6
|
import { witnessMapToFields } from '../acvm/deserialize.js';
|
|
7
7
|
import { Oracle, acvm, extractCallStack, toACVMWitness } from '../acvm/index.js';
|
|
@@ -18,7 +18,7 @@ export async function executeUnconstrainedFunction(
|
|
|
18
18
|
contractAddress: AztecAddress,
|
|
19
19
|
functionSelector: FunctionSelector,
|
|
20
20
|
args: Fr[],
|
|
21
|
-
log =
|
|
21
|
+
log = createLogger('simulator:unconstrained_execution'),
|
|
22
22
|
): Promise<AbiDecoded> {
|
|
23
23
|
log.verbose(`Executing unconstrained function ${contractAddress}:${functionSelector}(${artifact.name})`);
|
|
24
24
|
|