Skip to content

Commit

Permalink
chore(avm-simulator): avm's nested calls now stay and properly track …
Browse files Browse the repository at this point in the history
…PublicExecutionResult
  • Loading branch information
dbanks12 committed May 6, 2024
1 parent d4e54db commit dd3d5a7
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 116 deletions.
9 changes: 4 additions & 5 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ describe('e2e_avm_simulator', () => {
expect(await avmContract.methods.call_avm_from_acvm().simulate()).toEqual(123456n);
});

it('Can call ACVM function from AVM', async () => {
it.skip('Can call ACVM function from AVM', async () => {
expect(await avmContract.methods.call_acvm_from_avm().simulate()).toEqual(123456n);
});

Expand All @@ -113,7 +113,7 @@ describe('e2e_avm_simulator', () => {
await avmContract.methods.assert_unsiloed_nullifier_acvm(nullifier).send().wait();
});

it('AVM nested call to ACVM sees settled nullifiers', async () => {
it.skip('AVM nested call to ACVM sees settled nullifiers', async () => {
const nullifier = new Fr(123456);
await avmContract.methods.new_nullifier(nullifier).send().wait();
await avmContract.methods
Expand All @@ -122,7 +122,7 @@ describe('e2e_avm_simulator', () => {
.wait();
});

describe('Authwit', () => {
describe.skip('Authwit', () => {
it('Works if authwit provided', async () => {
const recipient = AztecAddress.random();
const action = avmContract.methods.test_authwit_send_money(
Expand Down Expand Up @@ -194,8 +194,7 @@ describe('e2e_avm_simulator', () => {
expect(tx.status).toEqual(TxStatus.MINED);
});

// TODO(4293): this should work! Fails in public kernel because both nullifiers are incorrectly being siloed by same address
it.skip('Should be able to emit the same unsiloed nullifier from two different contracts', async () => {
it('Should be able to emit the same unsiloed nullifier from two different contracts', async () => {
const nullifier = new Fr(1);
const tx = await avmContract.methods
.create_same_nullifier_in_nested_call(secondAvmContract.address, nullifier)
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/simulator/src/avm/avm_simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';

import { strict as assert } from 'assert';

import { isAvmBytecode } from '../public/transitional_adaptors.js';
import type { AvmContext } from './avm_context.js';
import { AvmContractCallResults } from './avm_message_call_result.js';
import { AvmExecutionError, InvalidProgramCounterError, NoBytecodeForContractError } from './errors.js';
Expand Down Expand Up @@ -32,6 +33,7 @@ export class AvmSimulator {
if (!bytecode) {
throw new NoBytecodeForContractError(this.context.environment.address);
}
assert(isAvmBytecode(bytecode), "AVM simulator can't execute non-AVM bytecode");

return await this.executeBytecode(bytecode);
}
Expand Down
5 changes: 4 additions & 1 deletion yarn-project/simulator/src/avm/journal/journal.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// TODO(5818): Rename file and all uses of "journal"
import { UnencryptedL2Log } from '@aztec/circuit-types';
import {
AztecAddress,
Expand Down Expand Up @@ -30,6 +31,7 @@ import {
type TracedUnencryptedL2Log,
} from './trace_types.js';

// TODO:(5818): do we need this type anymore?
/**
* Data held within the journal
*/
Expand Down Expand Up @@ -81,7 +83,7 @@ export class AvmPersistableStateManager {
/** Reference to node storage */
public readonly hostStorage: HostStorage;

// TODO: make members private once this is not used in transitional_adaptors.ts.
// TODO(5818): make members private once this is not used in transitional_adaptors.ts.
/** World State */
/** Public storage, including cached writes */
public publicStorage: PublicStorage;
Expand Down Expand Up @@ -327,6 +329,7 @@ export class AvmPersistableStateManager {
this.trace.acceptAndMerge(nestedJournal.trace);
}

// TODO:(5818): do we need this type anymore?
/**
* Access the current state of the journal
*
Expand Down
1 change: 1 addition & 0 deletions yarn-project/simulator/src/avm/journal/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class WorldStateAccessTrace {

constructor(parentTrace?: WorldStateAccessTrace) {
this.accessCounter = parentTrace ? parentTrace.accessCounter : 0;
// TODO(4805): consider tracking the parent's trace vector lengths so we can enforce limits
}

public getAccessCounter() {
Expand Down
35 changes: 19 additions & 16 deletions yarn-project/simulator/src/avm/opcodes/external_calls.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { FunctionSelector } from '@aztec/circuits.js';
import { FunctionSelector, Gas } from '@aztec/circuits.js';
import { padArrayEnd } from '@aztec/foundation/collection';

import { executePublicFunction } from '../../public/executor.js';
import {
convertPublicExecutionResult,
createPublicExecutionContext,
updateAvmContextFromPublicExecutionResult,
} from '../../public/transitional_adaptors.js';
import { convertAvmResultsToPxResult, createPublicExecution } from '../../public/transitional_adaptors.js';
import type { AvmContext } from '../avm_context.js';
import { gasLeftToGas, sumGas } from '../avm_gas.js';
import { Field, Uint8 } from '../avm_memory_types.js';
import { type AvmContractCallResults } from '../avm_message_call_result.js';
import { AvmSimulator } from '../avm_simulator.js';
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
import { Addressing } from './addressing_mode.js';
import { Instruction } from './instruction.js';
Expand Down Expand Up @@ -69,21 +65,29 @@ abstract class ExternalCall extends Instruction {
const totalGas = sumGas(this.gasCost(memoryOperations), allocatedGas);
context.machineState.consumeGas(totalGas);

// TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone.
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
const nestedContext = context.createNestedContractCallContext(
callAddress.toFr(),
calldata,
allocatedGas,
this.type,
FunctionSelector.fromField(functionSelector),
);
const pxContext = createPublicExecutionContext(nestedContext, calldata);
const pxResults = await executePublicFunction(pxContext, /*nested=*/ true);
const startSideEffectCounter = nestedContext.persistableState.trace.accessCounter;

const oldStyleExecution = createPublicExecution(startSideEffectCounter, nestedContext.environment, calldata);
const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
const pxResults = convertAvmResultsToPxResult(
nestedCallResults,
startSideEffectCounter,
oldStyleExecution,
Gas.from(allocatedGas),
nestedContext,
);
// store the old PublicExecutionResult object to maintain a recursive data structure for the old kernel
context.persistableState.transitionalExecutionResult.nestedExecutions.push(pxResults);
const nestedCallResults: AvmContractCallResults = convertPublicExecutionResult(pxResults);
updateAvmContextFromPublicExecutionResult(nestedContext, pxResults);
const nestedPersistableState = nestedContext.persistableState;
// END TRANSITIONAL

// const nestedContext = context.createNestedContractCallContext(
// callAddress.toFr(),
// calldata,
Expand All @@ -92,7 +96,6 @@ abstract class ExternalCall extends Instruction {
// FunctionSelector.fromField(functionSelector),
// );
// const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
// const nestedPersistableState = nestedContext.persistableState;

const success = !nestedCallResults.reverted;

Expand All @@ -114,9 +117,9 @@ abstract class ExternalCall extends Instruction {

// TODO: Should we merge the changes from a nested call in the case of a STATIC call?
if (success) {
context.persistableState.acceptNestedCallState(nestedPersistableState);
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
} else {
context.persistableState.rejectNestedCallState(nestedPersistableState);
context.persistableState.rejectNestedCallState(nestedContext.persistableState);
}

memory.assert(memoryOperations);
Expand Down
33 changes: 23 additions & 10 deletions yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { PackedValuesCache } from '../common/packed_values_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 { convertAvmResults, createAvmExecutionEnvironment, isAvmBytecode } from './transitional_adaptors.js';
import { convertAvmResultsToPxResult, createAvmExecutionEnvironment, isAvmBytecode } from './transitional_adaptors.js';

/**
* Execute a public function and return the execution result.
Expand All @@ -46,15 +46,20 @@ export async function executePublicFunction(
}

if (isAvmBytecode(bytecode)) {
return await executePublicFunctionAvm(context);
return await executeTopLevelPublicFunctionAvm(context);
} else {
return await executePublicFunctionAcvm(context, bytecode, nested);
}
}

async function executePublicFunctionAvm(executionContext: PublicExecutionContext): Promise<PublicExecutionResult> {
/**
* Execute a top-level public function call (the first call in an enqueued-call/execution-request) in the AVM.
* Translate the results back to the PublicExecutionResult format.
*/
async function executeTopLevelPublicFunctionAvm(executionContext: PublicExecutionContext): Promise<PublicExecutionResult> {
const address = executionContext.execution.contractAddress;
const selector = executionContext.execution.functionData.selector;
const startGas = executionContext.availableGas;
const log = createDebugLogger('aztec:simulator:public_execution');
log.verbose(`[AVM] Executing public external function ${address.toString()}:${selector}.`);

Expand All @@ -65,7 +70,12 @@ async function executePublicFunctionAvm(executionContext: PublicExecutionContext
executionContext.contractsDb,
executionContext.commitmentsDb,
);

// TODO(6207): add sideEffectCounter to persistableState construction
// or modify the PersistableStateManager to manage rollbacks across enqueued-calls and transactions.
const worldStateJournal = new AvmPersistableStateManager(hostStorage);
const startSideEffectCounter = executionContext.execution.callContext.sideEffectCounter;
worldStateJournal.trace.accessCounter = startSideEffectCounter;

const executionEnv = createAvmExecutionEnvironment(
executionContext.execution,
Expand All @@ -75,18 +85,21 @@ async function executePublicFunctionAvm(executionContext: PublicExecutionContext
executionContext.transactionFee,
);

const machineState = new AvmMachineState(executionContext.availableGas);
const context = new AvmContext(worldStateJournal, executionEnv, machineState);
const simulator = new AvmSimulator(context);
const machineState = new AvmMachineState(startGas);
const avmContext = new AvmContext(worldStateJournal, executionEnv, machineState);
const simulator = new AvmSimulator(avmContext);

const result = await simulator.execute();
const newWorldState = context.persistableState.flush();
const avmResult = await simulator.execute();

log.verbose(
`[AVM] ${address.toString()}:${selector} returned, reverted: ${result.reverted}, reason: ${result.revertReason}.`,
`[AVM] ${address.toString()}:${selector} returned, reverted: ${avmResult.reverted}, reason: ${
avmResult.revertReason
}.`,
);

return await convertAvmResults(executionContext, newWorldState, result, machineState);
return Promise.resolve(
convertAvmResultsToPxResult(avmResult, startSideEffectCounter, executionContext.execution, startGas, avmContext),
);
}

async function executePublicFunctionAcvm(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export class PublicExecutionContext extends TypedOracle {
public readonly header: Header,
public readonly globalVariables: GlobalVariables,
private readonly packedValuesCache: PackedValuesCache,
private readonly sideEffectCounter: SideEffectCounter,
// TRANSITIONAL: once AVM-ACVM interoperability is removed (fully functional AVM), sideEffectCounter can be made private
public readonly sideEffectCounter: SideEffectCounter,
public readonly stateDb: PublicStateDB,
public readonly contractsDb: PublicContractsDB,
public readonly commitmentsDb: CommitmentsDB,
Expand Down
Loading

0 comments on commit dd3d5a7

Please sign in to comment.