From 14e8c5c325ad8459e3c81cc7e443ca277dd072a9 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 30 Jan 2024 18:04:52 +0000 Subject: [PATCH] refactor(avm): make interpreter a function not a class (#4272) --- .../acir-simulator/src/avm/avm_context.ts | 8 +- .../acir-simulator/src/avm/index.test.ts | 5 +- .../src/avm/interpreter/interpreter.test.ts | 9 +- .../src/avm/interpreter/interpreter.ts | 82 +++++++------------ 4 files changed, 37 insertions(+), 67 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index aed883fef21..0fcb86cfde6 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -4,7 +4,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmExecutionEnvironment } from './avm_execution_environment.js'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmMessageCallResult } from './avm_message_call_result.js'; -import { AvmInterpreter, AvmInterpreterError } from './interpreter/index.js'; +import { AvmInterpreterError, executeAvm } from './interpreter/index.js'; import { AvmJournal } from './journal/journal.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { Instruction } from './opcodes/index.js'; @@ -49,10 +49,8 @@ export class AvmContext { const instructions: Instruction[] = decodeBytecode(bytecode); - const context = new AvmMachineState(this.executionEnvironment); - const interpreter = new AvmInterpreter(context, this.journal, instructions); - - return interpreter.run(); + const machineState = new AvmMachineState(this.executionEnvironment); + return executeAvm(machineState, this.journal, instructions); } /** diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index b43318d72ae..8fb3a49dab0 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -4,7 +4,7 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from './avm_machine_state.js'; import { initExecutionEnvironment } from './fixtures/index.js'; -import { AvmInterpreter } from './interpreter/interpreter.js'; +import { executeAvm } from './interpreter/interpreter.js'; import { AvmJournal } from './journal/journal.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; @@ -30,8 +30,7 @@ describe('avm', () => { // Execute instructions const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, journal, instructions); - const avmReturnData = await interpreter.run(); + const avmReturnData = await executeAvm(context, journal, instructions); expect(avmReturnData.reverted).toBe(false); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts index 79b814da07c..e5055cdf903 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -9,7 +9,7 @@ import { Add } from '../opcodes/arithmetic.js'; import { Jump, Return } from '../opcodes/control_flow.js'; import { Instruction } from '../opcodes/instruction.js'; import { CalldataCopy } from '../opcodes/memory.js'; -import { AvmInterpreter, InvalidProgramCounterError } from './interpreter.js'; +import { InvalidProgramCounterError, executeAvm } from './interpreter.js'; describe('interpreter', () => { let journal: MockProxy; @@ -28,8 +28,7 @@ describe('interpreter', () => { ]; const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(machineState, journal, instructions); - const avmReturnData = await interpreter.run(); + const avmReturnData = await executeAvm(machineState, journal, instructions); expect(avmReturnData.reverted).toBe(false); expect(avmReturnData.revertReason).toBeUndefined(); @@ -44,9 +43,7 @@ describe('interpreter', () => { const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(machineState, journal, instructions); - - const avmReturnData = await interpreter.run(); + const avmReturnData = await executeAvm(machineState, journal, instructions); expect(avmReturnData.reverted).toBe(true); expect(avmReturnData.revertReason).toBeInstanceOf(InvalidProgramCounterError); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts index 9073a0f0d6d..86385078cac 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts @@ -1,5 +1,3 @@ -import { Fr } from '@aztec/foundation/fields'; - import { strict as assert } from 'assert'; import { AvmMachineState } from '../avm_machine_state.js'; @@ -8,66 +6,44 @@ import { AvmJournal } from '../journal/index.js'; import { Instruction } from '../opcodes/index.js'; /** - * Avm Interpreter - * - * Executes an Avm context + * Run the avm + * @returns bool - successful execution will return true + * - reverted execution will return false + * - any other panic will throw */ -export class AvmInterpreter { - private instructions: Instruction[] = []; - private machineState: AvmMachineState; - private journal: AvmJournal; - - constructor(machineState: AvmMachineState, stateManager: AvmJournal, instructions: Instruction[]) { - this.machineState = machineState; - this.journal = stateManager; - this.instructions = instructions; - } - - /** - * Run the avm - * @returns bool - successful execution will return true - * - reverted execution will return false - * - any other panic will throw - */ - async run(): Promise { - assert(this.instructions.length > 0); - - try { - while (!this.machineState.halted) { - const instruction = this.instructions[this.machineState.pc]; - assert(!!instruction); // This should never happen +export async function executeAvm( + machineState: AvmMachineState, + journal: AvmJournal, + instructions: Instruction[] = [], +): Promise { + assert(instructions.length > 0); - await instruction.execute(this.machineState, this.journal); + try { + while (!machineState.halted) { + const instruction = instructions[machineState.pc]; + assert(!!instruction); // This should never happen - if (this.machineState.pc >= this.instructions.length) { - throw new InvalidProgramCounterError(this.machineState.pc, /*max=*/ this.instructions.length); - } - } + await instruction.execute(machineState, journal); - const returnData = this.machineState.getReturnData(); - if (this.machineState.reverted) { - return AvmMessageCallResult.revert(returnData); + if (machineState.pc >= instructions.length) { + throw new InvalidProgramCounterError(machineState.pc, /*max=*/ instructions.length); } + } - return AvmMessageCallResult.success(returnData); - } catch (_e) { - if (!(_e instanceof AvmInterpreterError)) { - throw _e; - } + const returnData = machineState.getReturnData(); + if (machineState.reverted) { + return AvmMessageCallResult.revert(returnData); + } - const revertReason: AvmInterpreterError = _e; - const revertData = this.machineState.getReturnData(); - return AvmMessageCallResult.revert(revertData, revertReason); + return AvmMessageCallResult.success(returnData); + } catch (_e) { + if (!(_e instanceof AvmInterpreterError)) { + throw _e; } - } - /** - * Get the return data from avm execution - * TODO: this should fail if the code has not been executed - * - maybe move the return in run into a variable and track it - */ - returnData(): Fr[] { - return this.machineState.getReturnData(); + const revertReason: AvmInterpreterError = _e; + const revertData = machineState.getReturnData(); + return AvmMessageCallResult.revert(revertData, revertReason); } }