diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index b49753c6357..4a51dad5570 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -8,7 +8,6 @@ pub const ALL_DIRECT: u8 = 0b00000000; pub const ZEROTH_OPERAND_INDIRECT: u8 = 0b00000001; pub const FIRST_OPERAND_INDIRECT: u8 = 0b00000010; pub const SECOND_OPERAND_INDIRECT: u8 = 0b00000100; -pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT; /// A simple representation of an AVM instruction for the purpose /// of generating an AVM bytecode from Brillig. diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index b8a2f65888d..97050ea3b23 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -175,6 +175,39 @@ contract AvmTest { dep::std::hash::pedersen_hash_with_separator(data, 20) } + /************************************************************************ + * ACVM interoperability + ************************************************************************/ + #[aztec(public)] + fn constant_field_acvm() -> pub Field { + 123456 + } + + #[aztec(public-vm)] + fn constant_field_avm() -> pub Field { + 123456 + } + + #[aztec(public-vm)] + fn call_acvm_from_avm() -> pub Field { + let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function( + context.this_address(), + FunctionSelector::from_signature("constant_field_acvm()"), + [] + ); + data_to_return[0] + } + + #[aztec(public)] + fn call_avm_from_acvm() -> pub Field { + let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function( + context.this_address(), + FunctionSelector::from_signature("constant_field_avm()"), + [] + ); + data_to_return[0] + } + /************************************************************************ * Contract instance ************************************************************************/ 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 6d1729f0292..f21c466d630 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 @@ -79,4 +79,10 @@ describe('e2e_avm_simulator', () => { }); }); }); + + describe('ACVM interoperability', () => { + it('Can execute ACVM function among AVM functions', async () => { + expect(await avmContact.methods.constant_field_acvm().simulate()).toEqual(123456n); + }); + }); }); diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index da083c15b97..fa1cbebee4c 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -230,8 +230,8 @@ export abstract class AbstractPhaseManager { while (executionStack.length) { const current = executionStack.pop()!; const isExecutionRequest = !isPublicExecutionResult(current); - const sideEffectCounter = lastSideEffectCounter(tx) + 1; + const result = isExecutionRequest ? await this.publicExecutor.simulate(current, this.globalVariables, sideEffectCounter) : current; diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 5dfc388a127..b0eb2a7737a 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -24,16 +24,67 @@ import { PackedArgsCache } from '../common/packed_args_cache.js'; import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from './db.js'; import { type PublicExecution, type PublicExecutionResult, checkValidStaticCall } from './execution.js'; import { PublicExecutionContext } from './public_execution_context.js'; +import { + isAvmBytecode, + temporaryConvertAvmResults, + temporaryCreateAvmExecutionEnvironment, +} from './transitional_migration.js'; /** * Execute a public function and return the execution result. */ export async function executePublicFunction( + context: PublicExecutionContext, + nested: boolean, +): Promise { + const bytecode = await context.contractsDb.getBytecode( + context.execution.contractAddress, + context.execution.functionData.selector, + ); + if (!bytecode) { + throw new Error( + `Bytecode not found for ${context.execution.contractAddress}:${context.execution.functionData.selector}`, + ); + } + + if (isAvmBytecode(bytecode)) { + return await executePublicFunctionAvm(context); + } else { + return await executePublicFunctionAcvm(context, bytecode, nested); + } +} + +async function executePublicFunctionAvm(executionContext: PublicExecutionContext): Promise { + // Temporary code to construct the AVM context + // These data structures will permeate across the simulator when the public executor is phased out + const hostStorage = new HostStorage( + executionContext.stateDb, + executionContext.contractsDb, + executionContext.commitmentsDb, + ); + const worldStateJournal = new AvmPersistableStateManager(hostStorage); + const executionEnv = temporaryCreateAvmExecutionEnvironment( + executionContext.execution, + executionContext.globalVariables, + ); + // TODO(@spalladino) Load initial gas from the public execution request + const machineState = new AvmMachineState(100_000, 100_000, 100_000); + + const context = new AvmContext(worldStateJournal, executionEnv, machineState); + const simulator = new AvmSimulator(context); + + const result = await simulator.execute(); + const newWorldState = context.persistableState.flush(); + // TODO(@spalladino) Read gas left from machineState and return it + return temporaryConvertAvmResults(executionContext.execution, newWorldState, result); +} + +async function executePublicFunctionAcvm( context: PublicExecutionContext, acir: Buffer, nested: boolean, - log = createDebugLogger('aztec:simulator:public_execution'), ): Promise { + const log = createDebugLogger('aztec:simulator:public_execution'); const execution = context.execution; const { contractAddress, functionData } = execution; const selector = functionData.selector; @@ -203,12 +254,6 @@ export class PublicExecutor { globalVariables: GlobalVariables, sideEffectCounter: number = 0, ): Promise { - const selector = execution.functionData.selector; - const acir = await this.contractsDb.getBytecode(execution.contractAddress, selector); - if (!acir) { - throw new Error(`Bytecode not found for ${execution.contractAddress}:${selector}`); - } - // Functions can request to pack arguments before calling other functions. // We use this cache to hold the packed arguments. const packedArgs = PackedArgsCache.create([]); @@ -224,7 +269,7 @@ export class PublicExecutor { this.commitmentsDb, ); - const executionResult = await executePublicFunction(context, acir, false /** nested */); + const executionResult = await executePublicFunction(context, /*nested=*/ false); if (executionResult.execution.callContext.isStaticCall) { checkValidStaticCall( diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index b2e5abe78d4..1b9a52d5c35 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -37,12 +37,12 @@ export class PublicExecutionContext extends TypedOracle { */ public readonly execution: PublicExecution, private readonly header: Header, - private readonly globalVariables: GlobalVariables, + public readonly globalVariables: GlobalVariables, private readonly packedArgsCache: PackedArgsCache, private readonly sideEffectCounter: SideEffectCounter, - private readonly stateDb: PublicStateDB, - private readonly contractsDb: PublicContractsDB, - private readonly commitmentsDb: CommitmentsDB, + public readonly stateDb: PublicStateDB, + public readonly contractsDb: PublicContractsDB, + public readonly commitmentsDb: CommitmentsDB, private log = createDebugLogger('aztec:simulator:public_execution_context'), ) { super(); @@ -192,14 +192,7 @@ export class PublicExecutionContext extends TypedOracle { ); const portalAddress = (await this.contractsDb.getPortalContractAddress(targetContractAddress)) ?? EthAddress.ZERO; - - const acir = await this.contractsDb.getBytecode(targetContractAddress, functionSelector); - if (!acir) { - throw new Error(`Bytecode not found for ${targetContractAddress}:${functionSelector}`); - } - - const functionData = new FunctionData(functionSelector, false); - + const functionData = new FunctionData(functionSelector, /*isPrivate=*/ false); const callContext = CallContext.from({ msgSender: isDelegateCall ? this.execution.callContext.msgSender : this.execution.contractAddress, storageContractAddress: isDelegateCall ? this.execution.contractAddress : targetContractAddress, @@ -229,7 +222,7 @@ export class PublicExecutionContext extends TypedOracle { this.log, ); - const childExecutionResult = await executePublicFunction(context, acir, true /** nested */); + const childExecutionResult = await executePublicFunction(context, /*nested=*/ true); if (isStaticCall) { checkValidStaticCall( diff --git a/yarn-project/simulator/src/avm/temporary_executor_migration.ts b/yarn-project/simulator/src/public/transitional_migration.ts similarity index 93% rename from yarn-project/simulator/src/avm/temporary_executor_migration.ts rename to yarn-project/simulator/src/public/transitional_migration.ts index 41ee7981a85..66e463f4189 100644 --- a/yarn-project/simulator/src/avm/temporary_executor_migration.ts +++ b/yarn-project/simulator/src/public/transitional_migration.ts @@ -1,4 +1,4 @@ -// All code in this file needs to die once the public executor is phased out. +// All code in this file needs to die once the public executor is phased out in favor of the AVM. import { UnencryptedFunctionL2Logs } from '@aztec/circuit-types'; import { ContractStorageRead, @@ -12,12 +12,12 @@ import { } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; +import { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js'; +import { type AvmContractCallResults } from '../avm/avm_message_call_result.js'; +import { type JournalData } from '../avm/journal/journal.js'; +import { Mov } from '../avm/opcodes/memory.js'; import { createSimulationError } from '../common/errors.js'; -import { type PublicExecution, type PublicExecutionResult } from '../public/execution.js'; -import { AvmExecutionEnvironment } from './avm_execution_environment.js'; -import { type AvmContractCallResults } from './avm_message_call_result.js'; -import { type JournalData } from './journal/journal.js'; -import { Mov } from './opcodes/memory.js'; +import { type PublicExecution, type PublicExecutionResult } from './execution.js'; /** Temporary Method *