Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,17 @@ jobs:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_card_game.test.ts

e2e-avm-simulator:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: AVM_ENABLED=1 cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_avm_simulator.test.ts

pxe:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -1275,6 +1286,7 @@ workflows:
- e2e-persistence: *e2e_test
- e2e-browser: *e2e_test
- e2e-card-game: *e2e_test
- e2e-avm-simulator: *e2e_test
- pxe: *e2e_test
- cli-docs-sandbox: *e2e_test
- guides-writing-an-account-contract: *e2e_test
Expand Down Expand Up @@ -1313,6 +1325,7 @@ workflows:
- e2e-persistence
- e2e-browser
- e2e-card-game
- e2e-avm-simulator
- pxe
- boxes-blank
- boxes-blank-react
Expand Down
3 changes: 3 additions & 0 deletions build-system/scripts/remote_run_script
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@ ssh -A -F $SSH_CONFIG_PATH $IP "
export ECR_DEPLOY_URL=$ECR_DEPLOY_URL
export ECR_URL=$ECR_URL
export BUILD_SYSTEM_DEBUG=${BUILD_SYSTEM_DEBUG:-}

# temp while we transitioning to avm
export AVM_ENABLED=${AVM_ENABLED:-}
./remote_runner $@
"
1 change: 1 addition & 0 deletions yarn-project/end-to-end/scripts/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
WS_BLOCK_CHECK_INTERVAL_MS: 50
PXE_BLOCK_POLLING_INTERVAL_MS: 50
ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500
AVM_ENABLED: ${AVM_ENABLED:-}
ports:
- '8080:8080'

Expand Down
35 changes: 35 additions & 0 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
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
Expand Up @@ -47,6 +47,8 @@ import {
} from '@aztec/simulator';
import { MerkleTreeOperations } from '@aztec/world-state';

import { env } from 'process';

import { getVerificationKeys } from '../mocks/verification_keys.js';
import { PublicProver } from '../prover/index.js';
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
Expand Down Expand Up @@ -157,7 +159,15 @@ export abstract class AbstractPhaseManager {
while (executionStack.length) {
const current = executionStack.pop()!;
const isExecutionRequest = !isPublicExecutionResult(current);
const result = isExecutionRequest ? await this.publicExecutor.simulate(current, this.globalVariables) : current;

// NOTE: temporary glue to incorporate avm execution calls
const simulator = (execution: PublicExecution, globalVariables: GlobalVariables) =>
env.AVM_ENABLED
? this.publicExecutor.simulateAvm(execution, globalVariables)
: this.publicExecutor.simulate(execution, globalVariables);

const result = isExecutionRequest ? await simulator(current, this.globalVariables) : current;

newUnencryptedFunctionLogs.push(result.unencryptedLogs);
const functionSelector = result.execution.functionData.selector.toString();
this.log(
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/simulator/src/avm/avm_execution_environment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GlobalVariables } from '@aztec/circuits.js';
import { FunctionSelector, GlobalVariables } from '@aztec/circuits.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
Expand Down Expand Up @@ -35,6 +35,8 @@ export class AvmExecutionEnvironment {
public readonly isDelegateCall: boolean,

public readonly calldata: Fr[],

public readonly temporaryFunctionSelector: FunctionSelector,
) {}

public deriveEnvironmentForNestedCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment {
Expand All @@ -52,6 +54,7 @@ export class AvmExecutionEnvironment {
this.isStaticCall,
this.isDelegateCall,
/*calldata=*/ calldata,
this.temporaryFunctionSelector,
);
}

Expand All @@ -70,6 +73,7 @@ export class AvmExecutionEnvironment {
/*isStaticCall=*/ true,
this.isDelegateCall,
/*calldata=*/ calldata,
this.temporaryFunctionSelector,
);
}

Expand All @@ -88,6 +92,7 @@ export class AvmExecutionEnvironment {
this.isStaticCall,
/*isDelegateCall=*/ true,
/*calldata=*/ calldata,
this.temporaryFunctionSelector,
);
}
}
4 changes: 2 additions & 2 deletions yarn-project/simulator/src/avm/avm_simulator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FunctionSelector } from '@aztec/circuits.js';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';

import { strict as assert } from 'assert';
Expand Down Expand Up @@ -72,7 +71,8 @@ export class AvmSimulator {
*/
private async fetchAndDecodeBytecode(): Promise<Instruction[]> {
// NOTE: the following is mocked as getPublicBytecode does not exist yet
const selector = new FunctionSelector(0);

const selector = this.context.environment.temporaryFunctionSelector;
const bytecode = await this.context.worldState.hostStorage.contractsDb.getBytecode(
this.context.environment.address,
selector,
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/simulator/src/avm/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GlobalVariables } from '@aztec/circuits.js';
import { FunctionSelector } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
Expand Down Expand Up @@ -52,6 +53,7 @@ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnviron
overrides?.isStaticCall ?? false,
overrides?.isDelegateCall ?? false,
overrides?.calldata ?? [],
overrides?.temporaryFunctionSelector ?? FunctionSelector.empty(),
);
}

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/avm/journal/host_storage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js';
import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../public/db.js';

/**
* Host storage
Expand Down
110 changes: 110 additions & 0 deletions yarn-project/simulator/src/avm/temporary_executor_migration.ts
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';
Copy link
Member Author

@Maddiaa0 Maddiaa0 Feb 8, 2024

Choose a reason for hiding this comment

The 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
Expand Up @@ -7,7 +7,7 @@ import { createDebugLogger } from '@aztec/foundation/log';
import { extractReturnWitness } from '../acvm/deserialize.js';
import { Oracle, acvm, extractCallStack, toACVMWitness } from '../acvm/index.js';
import { ExecutionError } from '../common/errors.js';
import { AcirSimulator } from '../index.js';
import { AcirSimulator } from './simulator.js';
import { ViewDataOracle } from './view_data_oracle.js';

// docs:start:execute_unconstrained_function
Expand Down
34 changes: 34 additions & 0 deletions yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Copy link
Member Author

Choose a reason for hiding this comment

The 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);
}
}
15 changes: 14 additions & 1 deletion yarn-project/types/src/abi/contract_artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Copy link
Member Author

Choose a reason for hiding this comment

The 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);
}

Expand All @@ -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');
Expand Down