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
5 changes: 2 additions & 3 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
/barretenberg/cpp/pil @Maddiaa0 @jeanmon @IlyasRidhuan @fcarreiro
# on changes to PIL-generated C++
/barretenberg/cpp/src/barretenberg/**/generated @jeanmon @IlyasRidhuan @fcarreiro
# on changes to AVM trace (C++ witness generator)
/barretenberg/cpp/src/barretenberg/vm/avm_trace @jeanmon @IlyasRidhuan @fcarreiro
# on changes to AVM C++ code
/barretenberg/cpp/src/barretenberg/vm @jeanmon @IlyasRidhuan @fcarreiro
# on changes to public context in aztec-nr
/noir-projects/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr @fcarreiro @dbanks12
/noir-projects/aztec-nr/aztec/src/context/public_context.nr @fcarreiro @dbanks12
Expand All @@ -24,7 +24,6 @@
/yarn-project/simulator/src/public/side_effect_trace.test.ts @fcarreiro @dbanks12
/yarn-project/simulator/src/public/side_effect_trace.ts @fcarreiro @dbanks12
/yarn-project/simulator/src/public/side_effect_trace_interface.ts @fcarreiro @dbanks12
/yarn-project/simulator/src/public/transitional_adaptors.ts @fcarreiro @dbanks12
# on changes to the AVM transpiler
/avm-transpiler/src @fcarreiro @dbanks12
#####################################################
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/bb-prover/src/avm_proving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ const proveAndVerifyAvmTestContract = async (
// TODO: pub somewhere more usable - copied from abstract phase manager
const getPublicInputs = (result: PublicExecutionResult): PublicCircuitPublicInputs => {
return PublicCircuitPublicInputs.from({
callContext: result.execution.callContext,
callContext: result.executionRequest.callContext,
proverAddress: AztecAddress.ZERO,
argsHash: computeVarArgsHash(result.execution.args),
argsHash: computeVarArgsHash(result.executionRequest.args),
newNoteHashes: padArrayEnd(result.newNoteHashes, NoteHash.empty(), MAX_NEW_NOTE_HASHES_PER_CALL),
newNullifiers: padArrayEnd(result.newNullifiers, Nullifier.empty(), MAX_NEW_NULLIFIERS_PER_CALL),
newL2ToL1Msgs: padArrayEnd(result.newL2ToL1Messages, L2ToL1Message.empty(), MAX_NEW_L2_TO_L1_MSGS_PER_CALL),
Expand Down
6 changes: 3 additions & 3 deletions yarn-project/prover-client/src/mocks/test_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { type DebugLogger } from '@aztec/foundation/log';
import { openTmpStore } from '@aztec/kv-store/utils';
import {
type ContractsDataSourcePublicDB,
type PublicExecution,
type PublicExecutionRequest,
type PublicExecutionResult,
PublicExecutionResultBuilder,
type PublicExecutor,
Expand Down Expand Up @@ -164,7 +164,7 @@ export class TestContext {
txValidator?: TxValidator<ProcessedTx>,
) {
const defaultExecutorImplementation = (
execution: PublicExecution,
execution: PublicExecutionRequest,
_globalVariables: GlobalVariables,
availableGas: Gas,
_txContext: TxContext,
Expand Down Expand Up @@ -204,7 +204,7 @@ export class TestContext {
blockProver?: BlockProver,
txValidator?: TxValidator<ProcessedTx>,
executorMock?: (
execution: PublicExecution,
execution: PublicExecutionRequest,
globalVariables: GlobalVariables,
availableGas: Gas,
txContext: TxContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type AvmRevertReason } from './errors.js';
/**
* Results of an contract call's execution in the AVM.
*/
export class AvmContractCallResults {
export class AvmContractCallResult {
constructor(public reverted: boolean, public output: Fr[], public revertReason?: AvmRevertReason) {}

toString(): string {
Expand Down
9 changes: 4 additions & 5 deletions yarn-project/simulator/src/avm/avm_execution_environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export class AvmContextInputs {
* Contains variables that remain constant during AVM execution
* These variables are provided by the public kernel circuit
*/
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): gas not implemented
export class AvmExecutionEnvironment {
private readonly calldataPrefixLength;
constructor(
Expand All @@ -35,15 +34,15 @@ export class AvmExecutionEnvironment {
public readonly gasSettings: GasSettings,
public readonly transactionFee: Fr,

// Function selector is temporary since eventually public contract bytecode will be one blob
// containing all functions, and function selector will become an application-level mechanism
// Function selector may be temporary since eventually public contract bytecode will likely be one
// blob containing all functions, and function selector will become an application-level mechanism
// (e.g. first few bytes of calldata + compiler-generated jump table)
public readonly temporaryFunctionSelector: FunctionSelector,
public readonly functionSelector: FunctionSelector,
) {
// We encode some extra inputs (AvmContextInputs) in calldata.
// This will have to go once we move away from one proof per call.
const inputs = new AvmContextInputs(
temporaryFunctionSelector.toField(),
functionSelector.toField(),
computeVarArgsHash(calldata),
isStaticCall,
).toFields();
Expand Down
23 changes: 11 additions & 12 deletions yarn-project/simulator/src/avm/avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { type Fieldable } from '@aztec/foundation/serialize';
import { mock } from 'jest-mock-extended';

import { type PublicSideEffectTraceInterface } from '../public/side_effect_trace_interface.js';
import { isAvmBytecode, markBytecodeAsAvm } from '../public/transitional_adaptors.js';
import { type AvmExecutionEnvironment } from './avm_execution_environment.js';
import { AvmMachineState } from './avm_machine_state.js';
import { type MemoryValue, TypeTag, type Uint8 } from './avm_memory_types.js';
import { AvmSimulator } from './avm_simulator.js';
import { isAvmBytecode, markBytecodeAsAvm } from './bytecode_utils.js';
import {
adjustCalldataIndex,
getAvmTestContractBytecode,
Expand Down Expand Up @@ -308,7 +308,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
it('selector', async () => {
const context = initContext({
env: initExecutionEnvironment({
temporaryFunctionSelector: FunctionSelector.fromSignature('check_selector()'),
functionSelector: FunctionSelector.fromSignature('check_selector()'),
}),
});
const bytecode = getAvmTestContractBytecode('check_selector');
Expand Down Expand Up @@ -345,8 +345,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {

describe('Side effects, world state, nested calls', () => {
const address = new Fr(1);
// TODO(dbanks12): should be able to make address and storage address different
const storageAddress = new Fr(1);
const storageAddress = new Fr(2);
const sender = new Fr(42);
const leafIndex = new Fr(7);
const slotNumber = 1; // must update Noir contract if changing this
Expand Down Expand Up @@ -411,7 +410,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {

describe.each([[/*exists=*/ false], [/*exists=*/ true]])('Nullifier checks', (exists: boolean) => {
const existsStr = exists ? 'DOES exist' : 'does NOT exist';
it(`Should return ${exists} (and be traced) when noteHash ${existsStr}`, async () => {
it(`Should return ${exists} (and be traced) when nullifier ${existsStr}`, async () => {
const calldata = [value0];
const context = createContext(calldata);
const bytecode = getAvmTestContractBytecode('nullifier_exists');
Expand All @@ -430,7 +429,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
const tracedLeafIndex = exists && !isPending ? leafIndex : Fr.ZERO;
expect(trace.traceNullifierCheck).toHaveBeenCalledWith(
storageAddress,
value0,
/*nullifier=*/ value0,
tracedLeafIndex,
exists,
isPending,
Expand All @@ -451,7 +450,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
? `at leafIndex=${mockAtLeafIndex.toNumber()} (exists at leafIndex=${leafIndex.toNumber()})`
: '';

it(`Should return ${expectFound} (and be traced) when noteHash ${existsStr} ${foundAtStr}`, async () => {
it(`Should return ${expectFound} (and be traced) when message ${existsStr} ${foundAtStr}`, async () => {
const calldata = [value0, leafIndex];
const context = createContext(calldata);
const bytecode = getAvmTestContractBytecode('l1_to_l2_msg_exists');
Expand All @@ -466,7 +465,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
expect(trace.traceL1ToL2MessageCheck).toHaveBeenCalledTimes(1);
expect(trace.traceL1ToL2MessageCheck).toHaveBeenCalledWith(
address,
/*noteHash=*/ value0,
/*msgHash=*/ value0,
leafIndex,
/*exists=*/ expectFound,
);
Expand All @@ -485,7 +484,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
expect(trace.traceNewNoteHash).toHaveBeenCalledTimes(1);
expect(trace.traceNewNoteHash).toHaveBeenCalledWith(
expect.objectContaining(storageAddress),
/*nullifier=*/ value0,
/*noteHash=*/ value0,
);
});

Expand Down Expand Up @@ -525,7 +524,7 @@ describe('AVM simulator: transpiled Noir contracts', () => {
// leafIndex is returned from DB call for nullifiers, so it is absent on DB miss
expect(trace.traceNullifierCheck).toHaveBeenCalledWith(
storageAddress,
value0,
/*nullifier=*/ value0,
/*leafIndex=*/ Fr.ZERO,
/*exists=*/ true,
/*isPending=*/ true,
Expand Down Expand Up @@ -639,8 +638,8 @@ describe('AVM simulator: transpiled Noir contracts', () => {
const results = await new AvmSimulator(context).executeBytecode(bytecode);
expect(results.reverted).toBe(false);

expect(await context.persistableState.peekStorage(address, listSlot0)).toEqual(calldata[0]);
expect(await context.persistableState.peekStorage(address, listSlot1)).toEqual(calldata[1]);
expect(await context.persistableState.peekStorage(storageAddress, listSlot0)).toEqual(calldata[0]);
expect(await context.persistableState.peekStorage(storageAddress, listSlot1)).toEqual(calldata[1]);

expect(trace.tracePublicStorageWrite).toHaveBeenCalledTimes(2);
expect(trace.tracePublicStorageWrite).toHaveBeenCalledWith(storageAddress, listSlot0, value0);
Expand Down
20 changes: 9 additions & 11 deletions yarn-project/simulator/src/avm/avm_simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';

import { strict as assert } from 'assert';

import { decompressBytecodeIfCompressed, isAvmBytecode } from '../public/transitional_adaptors.js';
import type { AvmContext } from './avm_context.js';
import { AvmContractCallResults } from './avm_message_call_result.js';
import { AvmContractCallResult } from './avm_contract_call_result.js';
import { decompressBytecodeIfCompressed, isAvmBytecode } from './bytecode_utils.js';
import {
AvmExecutionError,
InvalidProgramCounterError,
Expand All @@ -20,18 +20,16 @@ export class AvmSimulator {
private bytecode: Buffer | undefined;

constructor(private context: AvmContext) {
this.log = createDebugLogger(
`aztec:avm_simulator:core(f:${context.environment.temporaryFunctionSelector.toString()})`,
);
this.log = createDebugLogger(`aztec:avm_simulator:core(f:${context.environment.functionSelector.toString()})`);
}

/**
* Fetch the bytecode and execute it in the current context.
*/
public async execute(): Promise<AvmContractCallResults> {
public async execute(): Promise<AvmContractCallResult> {
const bytecode = await this.context.persistableState.getBytecode(
this.context.environment.address,
this.context.environment.temporaryFunctionSelector,
this.context.environment.functionSelector,
);

// This assumes that we will not be able to send messages to accounts without code
Expand All @@ -54,7 +52,7 @@ export class AvmSimulator {
* Executes the provided bytecode in the current context.
* This method is useful for testing and debugging.
*/
public async executeBytecode(bytecode: Buffer): Promise<AvmContractCallResults> {
public async executeBytecode(bytecode: Buffer): Promise<AvmContractCallResult> {
const decompressedBytecode = await decompressBytecodeIfCompressed(bytecode);
assert(isAvmBytecode(decompressedBytecode), "AVM simulator can't execute non-AVM bytecode");

Expand All @@ -66,7 +64,7 @@ export class AvmSimulator {
* Executes the provided instructions in the current context.
* This method is useful for testing and debugging.
*/
public async executeInstructions(instructions: Instruction[]): Promise<AvmContractCallResults> {
public async executeInstructions(instructions: Instruction[]): Promise<AvmContractCallResult> {
assert(instructions.length > 0);
const { machineState } = this.context;
try {
Expand Down Expand Up @@ -95,7 +93,7 @@ export class AvmSimulator {
const output = machineState.getOutput();
const reverted = machineState.getReverted();
const revertReason = reverted ? revertReasonFromExplicitRevert(output, this.context) : undefined;
const results = new AvmContractCallResults(reverted, output, revertReason);
const results = new AvmContractCallResult(reverted, output, revertReason);
this.log.debug(`Context execution results: ${results.toString()}`);
// Return results for processing by calling context
return results;
Expand All @@ -108,7 +106,7 @@ export class AvmSimulator {

const revertReason = revertReasonFromExceptionalHalt(err, this.context);
// Note: "exceptional halts" cannot return data, hence []
const results = new AvmContractCallResults(/*reverted=*/ true, /*output=*/ [], revertReason);
const results = new AvmContractCallResult(/*reverted=*/ true, /*output=*/ [], revertReason);
this.log.debug(`Context execution results: ${results.toString()}`);
// Return results for processing by calling context
return results;
Expand Down
32 changes: 32 additions & 0 deletions yarn-project/simulator/src/avm/bytecode_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { promisify } from 'util';
import { gunzip } from 'zlib';

import { Mov } from '../avm/opcodes/memory.js';

const AVM_MAGIC_SUFFIX = Buffer.from([
Mov.opcode, // opcode
0x00, // indirect
...Buffer.from('000018ca', 'hex'), // srcOffset
...Buffer.from('000018ca', 'hex'), // dstOffset
]);

export function markBytecodeAsAvm(bytecode: Buffer): Buffer {
return Buffer.concat([bytecode, AVM_MAGIC_SUFFIX]);
}

// This is just a helper function for the AVM simulator
export async function decompressBytecodeIfCompressed(bytecode: Buffer): Promise<Buffer> {
try {
return await promisify(gunzip)(bytecode);
} catch {
// If the bytecode is not compressed, the gunzip call will throw an error
// In this case, we assume the bytecode is not compressed and continue.
return Promise.resolve(bytecode);
}
}

export async function isAvmBytecode(bytecode: Buffer): Promise<boolean> {
const decompressedBytecode = await decompressBytecodeIfCompressed(bytecode);
const magicSize = AVM_MAGIC_SUFFIX.length;
return decompressedBytecode.subarray(-magicSize).equals(AVM_MAGIC_SUFFIX);
}
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/avm/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ function createRevertReason(message: string, context: AvmContext, nestedError?:
message,
/*failingFunction=*/ {
contractAddress: context.environment.address,
functionSelector: context.environment.temporaryFunctionSelector,
functionSelector: context.environment.functionSelector,
},
/*noirCallStack=*/ [...context.machineState.internalCallStack, context.machineState.pc].map(pc => `0.${pc}`),
/*options=*/ { cause: nestedError },
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/avm/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnviron
overrides?.calldata ?? [],
overrides?.gasSettings ?? GasSettings.empty(),
overrides?.transactionFee ?? Fr.ZERO,
overrides?.temporaryFunctionSelector ?? FunctionSelector.empty(),
overrides?.functionSelector ?? FunctionSelector.empty(),
);
}

Expand Down
18 changes: 10 additions & 8 deletions yarn-project/simulator/src/avm/journal/journal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { SerializableContractInstance } from '@aztec/types/contracts';

import { type TracedContractInstance } from '../../public/side_effect_trace.js';
import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
import { type AvmContractCallResult } from '../avm_contract_call_result.js';
import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
import { type AvmContractCallResults } from '../avm_message_call_result.js';
import { type HostStorage } from './host_storage.js';
import { NullifierManager } from './nullifiers.js';
import { PublicStorage } from './public_storage.js';
Expand All @@ -25,10 +25,11 @@ export class AvmPersistableStateManager {

constructor(
/** Reference to node storage */
private hostStorage: HostStorage,
private readonly hostStorage: HostStorage,
/** Side effect trace */
private trace: PublicSideEffectTraceInterface,
private readonly trace: PublicSideEffectTraceInterface,
/** Public storage, including cached writes */
// TODO(5818): make private once no longer accessed in executor
public readonly publicStorage: PublicStorage,
/** Nullifier set, including cached/recently-emitted nullifiers */
private readonly nullifiers: NullifierManager,
Expand Down Expand Up @@ -243,22 +244,23 @@ export class AvmPersistableStateManager {
*/
public async processNestedCall(
nestedState: AvmPersistableStateManager,
success: boolean,
nestedEnvironment: AvmExecutionEnvironment,
startGasLeft: Gas,
endGasLeft: Gas,
bytecode: Buffer,
avmCallResults: AvmContractCallResults,
avmCallResults: AvmContractCallResult,
) {
if (success) {
if (!avmCallResults.reverted) {
this.acceptNestedCallState(nestedState);
}
const functionName =
(await nestedState.hostStorage.contractsDb.getDebugFunctionName(
nestedEnvironment.address,
nestedEnvironment.temporaryFunctionSelector,
)) ?? `${nestedEnvironment.address}:${nestedEnvironment.temporaryFunctionSelector}`;
nestedEnvironment.functionSelector,
)) ?? `${nestedEnvironment.address}:${nestedEnvironment.functionSelector}`;

this.log.verbose(`[AVM] Calling nested function ${functionName}`);

this.trace.traceNestedCall(
nestedState.trace,
nestedEnvironment,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/avm/journal/public_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type PublicStorageReadResult = {
*/
export class PublicStorage {
/** Cached storage writes. */
private cache: PublicStorageCache;
private readonly cache: PublicStorageCache;

constructor(
/** Reference to node storage. Checked on parent cache-miss. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ describe('Accrued Substate', () => {
const tracedLeafIndex = exists && !isPending ? leafIndex : Fr.ZERO;
expect(trace.traceNullifierCheck).toHaveBeenCalledWith(
storageAddress,
value0,
/*nullifier=*/ value0,
tracedLeafIndex,
exists,
isPending,
Expand Down Expand Up @@ -292,7 +292,7 @@ describe('Accrued Substate', () => {
expect(trace.traceL1ToL2MessageCheck).toHaveBeenCalledTimes(1);
expect(trace.traceL1ToL2MessageCheck).toHaveBeenCalledWith(
address,
/*noteHash=*/ value0,
/*msgHash=*/ value0,
leafIndex,
/*exists=*/ expectFound,
);
Expand Down
Loading