diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index fe71b683719..8ec9c96f24d 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -63,7 +63,9 @@ describe('e2e_avm_simulator', () => { describe('From private', () => { it('Should enqueue a public function correctly', async () => { - await avmContract.methods.enqueue_public_from_private().simulate(); + const request = await avmContract.methods.enqueue_public_from_private().create(); + const simulation = await wallet.simulateTx(request, true); + expect(simulation.publicOutput!.revertReason).toBeUndefined(); }); }); diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index ddecd43c3b3..62a351878f8 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -156,9 +156,11 @@ export class AvmPersistableStateManager { */ public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr): Promise { this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`); + const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot); + this.log.debug(`leafSlot=${leafSlot}`); // Cache storage writes for later reference/reads this.publicStorage.write(contractAddress, slot, value); - const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot); + if (this.doMerkleOperations) { const result = await this.merkleTrees.writePublicStorage(leafSlot, value); assert(result !== undefined, 'Public data tree insertion error. You might want to disable doMerkleOperations.'); @@ -170,10 +172,13 @@ export class AvmPersistableStateManager { const lowLeafPath = lowLeafInfo.siblingPath; const newLeafPreimage = result.element as PublicDataTreeLeafPreimage; - let insertionPath; - + let insertionPath: Fr[] | undefined; if (!result.update) { insertionPath = result.insertionPath; + assert( + newLeafPreimage.value.equals(value), + `Value mismatch when performing public data write (got value: ${value}, value in ephemeral tree: ${newLeafPreimage.value})`, + ); } this.trace.tracePublicStorageWrite( @@ -201,8 +206,8 @@ export class AvmPersistableStateManager { public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise { const { value, cached } = await this.publicStorage.read(contractAddress, slot); this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`); - const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot); + this.log.debug(`leafSlot=${leafSlot}`); if (this.doMerkleOperations) { // Get leaf if present, low leaf if absent @@ -217,12 +222,18 @@ export class AvmPersistableStateManager { const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex); const leafPreimage = preimage as PublicDataTreeLeafPreimage; + this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`); this.log.debug( `leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`, ); - this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`); - if (!alreadyPresent) { + if (alreadyPresent) { + assert( + leafPreimage.value.equals(value), + `Value mismatch when performing public data read (got value: ${value}, value in ephemeral tree: ${leafPreimage.value})`, + ); + } else { + this.log.debug(`Slot has never been written before!`); // Sanity check that the leaf slot is skipped by low leaf when it doesn't exist assert( leafPreimage.slot.toBigInt() < leafSlot.toBigInt() && @@ -230,9 +241,6 @@ export class AvmPersistableStateManager { 'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist or is the max value.', ); } - this.log.debug( - `Tracing storage leaf preimage slot=${slot}, leafSlot=${leafSlot}, value=${value}, nextKey=${leafPreimage.nextSlot}, nextIndex=${leafPreimage.nextIndex}`, - ); // On non-existence, AVM circuit will need to recognize that leafPreimage.slot != leafSlot, // prove that this is a low leaf that skips leafSlot, and then prove membership of the leaf. this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, new Fr(leafIndex), leafPath); diff --git a/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts b/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts index 9905d454fcf..9b30dd016f3 100644 --- a/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts +++ b/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts @@ -51,7 +51,7 @@ import { Fr } from '@aztec/foundation/fields'; import { jsonStringify } from '@aztec/foundation/json-rpc'; import { createLogger } from '@aztec/foundation/log'; -import { assert } from 'console'; +import { strict as assert } from 'assert'; import { type AvmContractCallResult, type AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js'; import { type AvmExecutionEnvironment } from '../avm/avm_execution_environment.js'; @@ -197,20 +197,17 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI } public tracePublicStorageRead( - _contractAddress: AztecAddress, + contractAddress: AztecAddress, slot: Fr, value: Fr, leafPreimage: PublicDataTreeLeafPreimage = PublicDataTreeLeafPreimage.empty(), leafIndex: Fr = Fr.zero(), path: Fr[] = emptyPublicDataPath(), ) { - if (!leafIndex.equals(Fr.zero())) { - // if we have real merkle hint content, make sure the value matches the the provided preimage - assert(leafPreimage.value.equals(value), 'Value mismatch when tracing in public data write'); - } - this.avmCircuitHints.publicDataReads.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path)); - this.log.debug(`SLOAD cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`); + this.log.debug( + `Tracing storage read (address=${contractAddress}, slot=${slot}): value=${value} (counter=${this.sideEffectCounter})`, + ); this.incrementSideEffectCounter(); } @@ -224,10 +221,6 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI newLeafPreimage: PublicDataTreeLeafPreimage = PublicDataTreeLeafPreimage.empty(), insertionPath: Fr[] = emptyPublicDataPath(), ) { - if (!lowLeafIndex.equals(Fr.zero())) { - // if we have real merkle hint content, make sure the value matches the the provided preimage - assert(newLeafPreimage.value.equals(value), 'Value mismatch when tracing in public data read'); - } if ( this.publicDataWrites.length + this.previousSideEffectArrayLengths.publicDataWrites >= MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX @@ -248,7 +241,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI ); this.log.debug( - `Traced public data write (address=${contractAddress}, slot=${slot}, leafSlot=${leafSlot}): value=${value} (counter=${this.sideEffectCounter})`, + `Traced public data write (address=${contractAddress}, slot=${slot}): value=${value} (counter=${this.sideEffectCounter})`, ); this.incrementSideEffectCounter(); }