From 74c8c8ad018ec864f84dd3f94382babe110e171d Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Tue, 30 Apr 2024 21:16:11 +0000 Subject: [PATCH] chore(avm-simulator): track recursive public execution result in avm-simulator for integration with old kernel --- .../simulator/src/avm/journal/journal.ts | 96 ++++++++++++++++++- .../src/avm/opcodes/external_calls.ts | 2 + 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 5c21dd175a3b..b978242168a7 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -1,9 +1,20 @@ import { UnencryptedL2Log } from '@aztec/circuit-types'; -import { AztecAddress, EthAddress, L2ToL1Message } from '@aztec/circuits.js'; +import { + AztecAddress, + ContractStorageRead, + ContractStorageUpdateRequest, + EthAddress, + L2ToL1Message, + NoteHash, + Nullifier, + ReadRequest, + SideEffect, +} from '@aztec/circuits.js'; import { EventSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; +import { type PublicExecutionResult } from '../../index.js'; import { type HostStorage } from './host_storage.js'; import { Nullifiers } from './nullifiers.js'; import { PublicStorage } from './public_storage.js'; @@ -39,6 +50,21 @@ export type JournalData = { currentStorageValue: Map>; }; +// TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. +type PartialPublicExecutionResult = { + nullifierReadRequests: ReadRequest[]; + nullifierNonExistentReadRequests: ReadRequest[]; + newNoteHashes: NoteHash[]; + newL2ToL1Messages: L2ToL1Message[]; + startSideEffectCounter: number; + newNullifiers: Nullifier[]; + contractStorageReads: ContractStorageRead[]; + contractStorageUpdateRequests: ContractStorageUpdateRequest[]; + unencryptedLogs: UnencryptedL2Log[]; + unencryptedLogsHashes: SideEffect[]; + nestedExecutions: PublicExecutionResult[]; +}; + /** * A class to manage persistable AVM state for contract calls. * Maintains a cache of the current world state, @@ -67,11 +93,28 @@ export class AvmPersistableStateManager { public newL1Messages: L2ToL1Message[] = []; public newLogs: UnencryptedL2Log[] = []; + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + public transitionalExecutionResult: PartialPublicExecutionResult; + constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) { this.hostStorage = hostStorage; this.publicStorage = new PublicStorage(hostStorage.publicStateDb, parent?.publicStorage); this.nullifiers = new Nullifiers(hostStorage.commitmentsDb, parent?.nullifiers); this.trace = new WorldStateAccessTrace(parent?.trace); + + this.transitionalExecutionResult = { + nullifierReadRequests: [], + nullifierNonExistentReadRequests: [], + newNoteHashes: [], + newL2ToL1Messages: [], + startSideEffectCounter: this.trace.accessCounter, + newNullifiers: [], + contractStorageReads: [], + contractStorageUpdateRequests: [], + unencryptedLogs: [], + unencryptedLogsHashes: [], + nestedExecutions: [], + }; } /** @@ -92,6 +135,12 @@ export class AvmPersistableStateManager { this.log.debug(`storage(${storageAddress})@${slot} <- ${value}`); // Cache storage writes for later reference/reads this.publicStorage.write(storageAddress, slot, value); + + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.contractStorageUpdateRequests.push( + new ContractStorageUpdateRequest(slot, value, this.trace.accessCounter), + ); + // Trace all storage writes (even reverted ones) this.trace.tracePublicStorageWrite(storageAddress, slot, value); } @@ -106,6 +155,12 @@ export class AvmPersistableStateManager { public async readStorage(storageAddress: Fr, slot: Fr): Promise { const [exists, value] = await this.publicStorage.read(storageAddress, slot); this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}.`); + + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.contractStorageReads.push( + new ContractStorageRead(slot, value, this.trace.accessCounter), + ); + // We want to keep track of all performed reads (even reverted ones) this.trace.tracePublicStorageRead(storageAddress, slot, value, exists); return Promise.resolve(value); @@ -133,6 +188,9 @@ export class AvmPersistableStateManager { * @param noteHash - the unsiloed note hash to write */ public writeNoteHash(storageAddress: Fr, noteHash: Fr) { + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.newNoteHashes.push(new NoteHash(noteHash, this.trace.accessCounter)); + this.log.debug(`noteHashes(${storageAddress}) += @${noteHash}.`); this.trace.traceNewNoteHash(storageAddress, noteHash); } @@ -148,6 +206,16 @@ export class AvmPersistableStateManager { this.log.debug( `nullifiers(${storageAddress})@${nullifier} ?? leafIndex: ${leafIndex}, pending: ${isPending}, exists: ${exists}.`, ); + + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + if (exists) { + this.transitionalExecutionResult.nullifierReadRequests.push(new ReadRequest(nullifier, this.trace.accessCounter)); + } else { + this.transitionalExecutionResult.nullifierNonExistentReadRequests.push( + new ReadRequest(nullifier, this.trace.accessCounter), + ); + } + this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex); return Promise.resolve(exists); } @@ -158,6 +226,11 @@ export class AvmPersistableStateManager { * @param nullifier - the unsiloed nullifier to write */ public async writeNullifier(storageAddress: Fr, nullifier: Fr) { + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.newNullifiers.push( + new Nullifier(nullifier, this.trace.accessCounter, Fr.ZERO), + ); + this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`); // Cache pending nullifiers for later access await this.nullifiers.append(storageAddress, nullifier); @@ -189,18 +262,31 @@ export class AvmPersistableStateManager { public writeL1Message(recipient: EthAddress | Fr, content: Fr) { this.log.debug(`L1Messages(${recipient}) += ${content}.`); const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient); - this.newL1Messages.push(new L2ToL1Message(recipientAddress, content)); + const message = new L2ToL1Message(recipientAddress, content); + this.newL1Messages.push(message); + + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.newL2ToL1Messages.push(message); } public writeLog(contractAddress: Fr, event: Fr, log: Fr[]) { this.log.debug(`UnencryptedL2Log(${contractAddress}) += event ${event} with ${log.length} fields.`); - const L2log = new UnencryptedL2Log( + const ulog = new UnencryptedL2Log( AztecAddress.fromField(contractAddress), EventSelector.fromField(event), Buffer.concat(log.map(f => f.toBuffer())), ); - this.newLogs.push(L2log); - this.trace.traceNewLog(Fr.fromBuffer(L2log.hash())); + const logHash = Fr.fromBuffer(ulog.hash()); + + // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone. + this.transitionalExecutionResult.unencryptedLogs.push(ulog); + // this duplicates exactly what happens in the trace just for the purpose of transitional integration with the kernel + this.transitionalExecutionResult.unencryptedLogsHashes.push( + new SideEffect(logHash, new Fr(this.trace.accessCounter)), + ); + + this.newLogs.push(ulog); + this.trace.traceNewLog(logHash); } /** diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.ts index 5985f9f78adb..9d2a8fa68d4b 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.ts @@ -79,6 +79,8 @@ abstract class ExternalCall extends Instruction { ); const pxContext = createPublicExecutionContext(nestedContext, calldata); const pxResults = await executePublicFunction(pxContext, /*nested=*/ true); + // store the old PublicExecutionResult object to maintain a recursive data structure for the old kernel + context.persistableState.transitionalExecutionResult.nestedExecutions.push(pxResults); const nestedCallResults: AvmContractCallResults = convertPublicExecutionResult(pxResults); updateAvmContextFromPublicExecutionResult(nestedContext, pxResults); const nestedPersistableState = nestedContext.persistableState;