diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index b51234f482f..3a47c4adebb 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -145,6 +145,15 @@ export class AvmPersistableStateManager { this.publicStorage.write(storageAddress, slot, value); // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit + // The current info to the kernel clears any previous read or write request. + this.transitionalExecutionResult.contractStorageReads = + this.transitionalExecutionResult.contractStorageReads.filter( + read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress), + ); + this.transitionalExecutionResult.contractStorageUpdateRequests = + this.transitionalExecutionResult.contractStorageUpdateRequests.filter( + update => !update.storageSlot.equals(slot) || !update.contractAddress!.equals(storageAddress), + ); this.transitionalExecutionResult.contractStorageUpdateRequests.push( new ContractStorageUpdateRequest(slot, value, this.trace.accessCounter, storageAddress), ); @@ -165,9 +174,17 @@ export class AvmPersistableStateManager { this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}, cached: ${cached}.`); // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit - this.transitionalExecutionResult.contractStorageReads.push( - new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress), - ); + // The current info to the kernel kernel does not consider cached reads. + if (!cached) { + // The current info to the kernel removes any previous reads to the same slot. + this.transitionalExecutionResult.contractStorageReads = + this.transitionalExecutionResult.contractStorageReads.filter( + read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress), + ); + this.transitionalExecutionResult.contractStorageReads.push( + new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress), + ); + } // We want to keep track of all performed reads (even reverted ones) this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached); diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 846f693eedf..10ec1e7ad93 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -46,7 +46,7 @@ export async function executePublicFunction( } if (isAvmBytecode(bytecode)) { - return await executeTopLevelPublicFunctionAvm(context, bytecode, nested); + return await executeTopLevelPublicFunctionAvm(context, bytecode); } else { return await executePublicFunctionAcvm(context, bytecode, nested); } @@ -57,11 +57,8 @@ export async function executePublicFunction( * Translate the results back to the PublicExecutionResult format. */ async function executeTopLevelPublicFunctionAvm( - executionContext: PublicExecutionContext, bytecode: Buffer, - nested: boolean, -, ): Promise { const address = executionContext.execution.contractAddress; const selector = executionContext.execution.functionData.selector; @@ -97,12 +94,10 @@ async function executeTopLevelPublicFunctionAvm( const avmResult = await simulator.executeBytecode(bytecode); - if (!nested) { - // Commit the journals state to the DBs if this is the top-level execution. - // Observe that this will write all the state changes to the DBs, not only the latest for each slot. - // However, the underlying DB keep a cache and will only write the latest state to disk. - await context.persistableState.publicStorage.commitToDB(); - } + // Commit the journals state to the DBs since this is a top-level execution. + // Observe that this will write all the state changes to the DBs, not only the latest for each slot. + // However, the underlying DB keep a cache and will only write the latest state to disk. + await avmContext.persistableState.publicStorage.commitToDB(); log.verbose( `[AVM] ${address.toString()}:${selector} returned, reverted: ${avmResult.reverted}, reason: ${ @@ -110,8 +105,13 @@ async function executeTopLevelPublicFunctionAvm( }.`, ); - return - convertAvmResultsToPxResult(avmResult, startSideEffectCounter, executionContext.execution, startGas, avmContext); + return convertAvmResultsToPxResult( + avmResult, + startSideEffectCounter, + executionContext.execution, + startGas, + avmContext, + ); } async function executePublicFunctionAcvm( diff --git a/yarn-project/simulator/src/public/transitional_adaptors.ts b/yarn-project/simulator/src/public/transitional_adaptors.ts index 51cfefc8c5e..5e241a6a315 100644 --- a/yarn-project/simulator/src/public/transitional_adaptors.ts +++ b/yarn-project/simulator/src/public/transitional_adaptors.ts @@ -1,31 +1,21 @@ // All code in this file needs to die once the public executor is phased out in favor of the AVM. -import { UnencryptedFunctionL2Logs, UnencryptedL2Log } from '@aztec/circuit-types'; +import { UnencryptedFunctionL2Logs } from '@aztec/circuit-types'; import { CallContext, - ContractStorageRead, - ContractStorageUpdateRequest, FunctionData, type Gas, type GasSettings, type GlobalVariables, type Header, - L2ToL1Message, - NoteHash, - Nullifier, - ReadRequest, - SideEffect, } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { type AvmContext } from '../avm/avm_context.js'; import { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js'; -import { type AvmMachineState } from '../avm/avm_machine_state.js'; -import { AvmContractCallResults } from '../avm/avm_message_call_result.js'; -import { type JournalData } from '../avm/journal/journal.js'; +import { type AvmContractCallResults } from '../avm/avm_message_call_result.js'; import { Mov } from '../avm/opcodes/memory.js'; import { createSimulationError } from '../common/errors.js'; import { type PublicExecution, type PublicExecutionResult } from './execution.js'; -import { type PublicExecutionContext } from './public_execution_context.js'; /** * Convert a PublicExecution(Environment) object to an AvmExecutionEnvironment @@ -109,106 +99,6 @@ export function convertAvmResultsToPxResult( }; } -/** - * Convert the result of an AVM contract call to a PublicExecutionResult for the public kernel - * - * @param execution - * @param newWorldState - * @param result - * @returns - */ -export function convertAvmResults( - executionContext: PublicExecutionContext, - newWorldState: JournalData, - result: AvmContractCallResults, - endMachineState: AvmMachineState, -): PublicExecutionResult { - const execution = executionContext.execution; - - let contractStorageReads: ContractStorageRead[] = newWorldState.storageReads - .filter(read => !read.cached) // The kernel doesn't consider cached reads. - .map(read => new ContractStorageRead(read.slot, read.value, read.counter.toNumber(), read.storageAddress)); - let contractStorageUpdateRequests: ContractStorageUpdateRequest[] = newWorldState.storageWrites.map( - write => new ContractStorageUpdateRequest(write.slot, write.value, write.counter.toNumber(), write.storageAddress), - ); - - // The current kernel expects only reads that are not overwritten later. - // (This implementation is cuadratic and can be improved if needed.) - contractStorageReads = contractStorageReads.filter( - read => !contractStorageUpdateRequests.some(update => update.storageSlot.equals(read.storageSlot)), - ); - // The current kernel expects only writes that are not overwritten later. - contractStorageUpdateRequests = contractStorageUpdateRequests.filter( - update => - !contractStorageUpdateRequests.some( - otherUpdate => - otherUpdate.storageSlot.equals(update.storageSlot) && - otherUpdate.sideEffectCounter! > update.sideEffectCounter!, - ), - ); - - const newNoteHashes = newWorldState.newNoteHashes.map( - noteHash => new NoteHash(noteHash.noteHash, noteHash.counter.toNumber()), - ); - const nullifierReadRequests: ReadRequest[] = newWorldState.nullifierChecks - .filter(nullifierCheck => nullifierCheck.exists) - .map(nullifierCheck => new ReadRequest(nullifierCheck.nullifier, nullifierCheck.counter.toNumber())); - const nullifierNonExistentReadRequests: ReadRequest[] = newWorldState.nullifierChecks - .filter(nullifierCheck => !nullifierCheck.exists) - .map(nullifierCheck => new ReadRequest(nullifierCheck.nullifier, nullifierCheck.counter.toNumber())); - const newNullifiers: Nullifier[] = newWorldState.newNullifiers.map( - tracedNullifier => - new Nullifier( - /*value=*/ tracedNullifier.nullifier, - tracedNullifier.counter.toNumber(), - /*noteHash=*/ Fr.ZERO, // NEEDED? - ), - ); - const unencryptedLogs: UnencryptedFunctionL2Logs = new UnencryptedFunctionL2Logs( - newWorldState.newLogs.map(log => new UnencryptedL2Log(log.contractAddress, log.selector, log.data)), - ); - const unencryptedLogsHashes = newWorldState.newLogsHashes.map( - logHash => new SideEffect(logHash.logHash, logHash.counter), - ); - const newL2ToL1Messages = newWorldState.newL1Messages.map(m => new L2ToL1Message(m.recipient, m.content)); - - const returnValues = result.output; - - // TODO: Support nested executions. - const nestedExecutions: PublicExecutionResult[] = []; - const allUnencryptedLogs = unencryptedLogs; - const startSideEffectCounter = new Fr(executionContext.execution.callContext.sideEffectCounter); - const endSideEffectCounter = new Fr(newWorldState.sideEffectCounter); - - return { - execution, - nullifierReadRequests, - nullifierNonExistentReadRequests, - newNoteHashes, - newL2ToL1Messages, - startSideEffectCounter, - endSideEffectCounter, - newNullifiers, - contractStorageReads, - contractStorageUpdateRequests, - returnValues, - nestedExecutions, - unencryptedLogsHashes, - unencryptedLogs, - unencryptedLogPreimagesLength: new Fr(unencryptedLogs.getSerializedLength()), - allUnencryptedLogs, - reverted: result.reverted, - revertReason: result.revertReason ? createSimulationError(result.revertReason) : undefined, - startGasLeft: executionContext.availableGas, - endGasLeft: endMachineState.gasLeft, - transactionFee: executionContext.transactionFee, - }; -} - -export function convertPublicExecutionResult(res: PublicExecutionResult): AvmContractCallResults { - return new AvmContractCallResults(res.reverted, res.returnValues, res.revertReason); -} - const AVM_MAGIC_SUFFIX = Buffer.from([ Mov.opcode, // opcode 0x00, // indirect