-
Notifications
You must be signed in to change notification settings - Fork 597
feat(avm): introduce small e2e test #4470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ec44f7a
fd4b879
b395acf
909b4f8
8ec7f21
1297a98
cae3239
664515c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import { DebugLogger, Fr, Wallet } from '@aztec/aztec.js'; | ||
| import { AvmTestContract } from '@aztec/noir-contracts'; | ||
|
|
||
| import { setup } from './fixtures/utils.js'; | ||
|
|
||
| process.env.AVM_ENABLED = 'absofrigginlutely'; | ||
|
|
||
| describe('e2e_nested_contract', () => { | ||
| let wallet: Wallet; | ||
| let logger: DebugLogger; | ||
| let teardown: () => Promise<void>; | ||
|
|
||
| beforeEach(async () => { | ||
| ({ teardown, wallet, logger } = await setup()); | ||
| }, 100_000); | ||
|
|
||
| afterEach(() => teardown()); | ||
|
|
||
| describe('Call succeeds through AVM', () => { | ||
| let avmContact: AvmTestContract; | ||
|
|
||
| beforeEach(async () => { | ||
| avmContact = await AvmTestContract.deploy(wallet).send().deployed(); | ||
| }, 50_000); | ||
|
|
||
| it('Calls an avm contract', async () => { | ||
| const a = new Fr(1); | ||
| const b = new Fr(2); | ||
|
|
||
| logger('Calling avm_addArgsReturn...'); | ||
| await avmContact.methods.avm_addArgsReturn(a, b).send().wait(); | ||
| logger('Success'); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // All code in this file needs to die once the public executor is phased out. | ||
| import { FunctionL2Logs } from '@aztec/circuit-types'; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everything in this file will be phased out as avm becomes standard, getting into trunk will allow functionality to be gradually added |
||
| import { | ||
| ContractStorageRead, | ||
| ContractStorageUpdateRequest, | ||
| GlobalVariables, | ||
| SideEffect, | ||
| SideEffectLinkedToNoteHash, | ||
| } from '@aztec/circuits.js'; | ||
| import { Fr } from '@aztec/foundation/fields'; | ||
|
|
||
| import { PublicExecution, PublicExecutionResult } from '../public/execution.js'; | ||
| import { AvmExecutionEnvironment } from './avm_execution_environment.js'; | ||
| import { AvmContractCallResults } from './avm_message_call_result.js'; | ||
| import { JournalData } from './journal/journal.js'; | ||
|
|
||
| /** Temporary Method | ||
| * | ||
| * Convert a PublicExecution(Environment) object to an AvmExecutionEnvironment | ||
| * | ||
| * @param current | ||
| * @param globalVariables | ||
| * @returns | ||
| */ | ||
| export function temporaryCreateAvmExecutionEnvironment( | ||
| current: PublicExecution, | ||
| globalVariables: GlobalVariables, | ||
| ): AvmExecutionEnvironment { | ||
| // Function selector is included temporarily until noir codegens public contract bytecode in a single blob | ||
| return new AvmExecutionEnvironment( | ||
| current.contractAddress, | ||
| current.callContext.storageContractAddress, | ||
| current.callContext.msgSender, // TODO: origin is not available | ||
| current.callContext.msgSender, | ||
| current.callContext.portalContractAddress, | ||
| /*feePerL1Gas=*/ Fr.zero(), | ||
| /*feePerL2Gas=*/ Fr.zero(), | ||
| /*feePerDaGas=*/ Fr.zero(), | ||
| /*contractCallDepth=*/ Fr.zero(), | ||
| globalVariables, | ||
| current.callContext.isStaticCall, | ||
| current.callContext.isDelegateCall, | ||
| current.args, | ||
| current.functionData.selector, | ||
| ); | ||
| } | ||
|
|
||
| /** Temporary Method | ||
| * | ||
| * Convert the result of an AVM contract call to a PublicExecutionResult for the public kernel | ||
| * | ||
| * @param execution | ||
| * @param newWorldState | ||
| * @param result | ||
| * @returns | ||
| */ | ||
| export function temporaryConvertAvmResults( | ||
| execution: PublicExecution, | ||
| newWorldState: JournalData, | ||
| result: AvmContractCallResults, | ||
| ): PublicExecutionResult { | ||
| const newCommitments = newWorldState.newNoteHashes.map(noteHash => new SideEffect(noteHash, Fr.zero())); | ||
|
|
||
| const contractStorageReads: ContractStorageRead[] = []; | ||
| const reduceStorageReadRequests = (contractAddress: bigint, storageReads: Map<bigint, Fr[]>) => { | ||
| return storageReads.forEach((innerArray, key) => { | ||
| innerArray.forEach(value => { | ||
| contractStorageReads.push(new ContractStorageRead(new Fr(key), new Fr(value), 0)); | ||
| }); | ||
| }); | ||
| }; | ||
| newWorldState.storageReads.forEach((storageMap: Map<bigint, Fr[]>, address: bigint) => | ||
| reduceStorageReadRequests(address, storageMap), | ||
| ); | ||
|
|
||
| const contractStorageUpdateRequests: ContractStorageUpdateRequest[] = []; | ||
| const reduceStorageUpdateRequests = (contractAddress: bigint, storageUpdateRequests: Map<bigint, Fr[]>) => { | ||
| return storageUpdateRequests.forEach((innerArray, key) => { | ||
| innerArray.forEach(value => { | ||
| contractStorageUpdateRequests.push( | ||
| new ContractStorageUpdateRequest(new Fr(key), /*TODO: old value not supported */ Fr.zero(), new Fr(value), 0), | ||
| ); | ||
| }); | ||
| }); | ||
| }; | ||
| newWorldState.storageWrites.forEach((storageMap: Map<bigint, Fr[]>, address: bigint) => | ||
| reduceStorageUpdateRequests(address, storageMap), | ||
| ); | ||
|
|
||
| const returnValues = result.output; | ||
|
|
||
| // TODO(follow up in pr tree): NOT SUPPORTED YET, make sure hashing and log resolution is done correctly | ||
| // Disabled. | ||
| const nestedExecutions: PublicExecutionResult[] = []; | ||
| const newNullifiers: SideEffectLinkedToNoteHash[] = []; | ||
| const unencryptedLogs = FunctionL2Logs.empty(); | ||
| const newL2ToL1Messages = newWorldState.newL1Messages.map(() => Fr.zero()); | ||
|
|
||
| return { | ||
| execution, | ||
| newCommitments, | ||
| newL2ToL1Messages, | ||
| newNullifiers, | ||
| contractStorageReads, | ||
| contractStorageUpdateRequests, | ||
| returnValues, | ||
| nestedExecutions, | ||
| unencryptedLogs, | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,15 @@ import { GlobalVariables, Header, PublicCircuitPublicInputs } from '@aztec/circu | |
| import { createDebugLogger } from '@aztec/foundation/log'; | ||
|
|
||
| import { Oracle, acvm, extractCallStack, extractReturnWitness } from '../acvm/index.js'; | ||
| import { AvmContext } from '../avm/avm_context.js'; | ||
| import { AvmMachineState } from '../avm/avm_machine_state.js'; | ||
| import { AvmSimulator } from '../avm/avm_simulator.js'; | ||
| import { HostStorage } from '../avm/journal/host_storage.js'; | ||
| import { AvmWorldStateJournal } from '../avm/journal/index.js'; | ||
| import { | ||
| temporaryConvertAvmResults, | ||
| temporaryCreateAvmExecutionEnvironment, | ||
| } from '../avm/temporary_executor_migration.js'; | ||
| import { ExecutionError, createSimulationError } from '../common/errors.js'; | ||
| import { SideEffectCounter } from '../common/index.js'; | ||
| import { PackedArgsCache } from '../common/packed_args_cache.js'; | ||
|
|
@@ -121,4 +130,29 @@ export class PublicExecutor { | |
| throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during public execution')); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Executes a public execution request in the avm. | ||
| * @param execution - The execution to run. | ||
| * @param globalVariables - The global variables to use. | ||
| * @returns The result of the run plus all nested runs. | ||
| */ | ||
| public async simulateAvm( | ||
| execution: PublicExecution, | ||
| globalVariables: GlobalVariables, | ||
| ): Promise<PublicExecutionResult> { | ||
| // Temporary code to construct the AVM context | ||
| // These data structures will permiate across the simulator when the public executor is phased out | ||
| const hostStorage = new HostStorage(this.stateDb, this.contractsDb, this.commitmentsDb); | ||
| const worldStateJournal = new AvmWorldStateJournal(hostStorage); | ||
| const executionEnv = temporaryCreateAvmExecutionEnvironment(execution, globalVariables); | ||
| const machineState = new AvmMachineState(0, 0, 0); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gas not enabled |
||
|
|
||
| const context = new AvmContext(worldStateJournal, executionEnv, machineState); | ||
| const simulator = new AvmSimulator(context); | ||
|
|
||
| const result = await simulator.execute(); | ||
| const newWorldState = context.worldState.flush(); | ||
| return temporaryConvertAvmResults(execution, newWorldState, result); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,7 +103,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction): FunctionArt | |
|
|
||
| // If the function is not unconstrained, the first item is inputs or CallContext which we should omit | ||
| let parameters = fn.abi.parameters.map(generateFunctionParameter); | ||
| if (functionType !== 'unconstrained') { | ||
| if (hasKernelFunctionInputs(parameters)) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevents the indiscriminate stripping of the first noir argument present when generating the abi ( it removes the context ) |
||
| parameters = parameters.slice(1); | ||
| } | ||
|
|
||
|
|
@@ -125,6 +125,19 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction): FunctionArt | |
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the first parameter is kernel function inputs. | ||
| * | ||
| * Noir macros #[aztec(private|public)] inject the following code | ||
| * fn <name>(inputs: <Public|Private>ContextInputs, ...otherparams) {} | ||
| * | ||
| * Return true if this injected parameter is found | ||
| */ | ||
| function hasKernelFunctionInputs(params: ABIParameter[]): boolean { | ||
| const firstParam = params[0]; | ||
| return firstParam?.type.kind === 'struct' && firstParam.type.path.includes('ContextInputs'); | ||
| } | ||
|
|
||
| /** Validates contract artifact instance, throwing on error. */ | ||
| function validateContractArtifact(contract: ContractArtifact) { | ||
| const constructorArtifact = contract.functions.find(({ name }) => name === 'constructor'); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.