diff --git a/yarn-project/circuit-types/src/simulation_error.ts b/yarn-project/circuit-types/src/simulation_error.ts index 3e84bbdb60e6..47ecfc1629f6 100644 --- a/yarn-project/circuit-types/src/simulation_error.ts +++ b/yarn-project/circuit-types/src/simulation_error.ts @@ -19,7 +19,7 @@ export interface FailingFunction { /** * The selector of the function that failed. */ - functionSelector: FunctionSelector; + functionSelector?: FunctionSelector; /** * The name of the function that failed. */ @@ -160,6 +160,7 @@ export class SimulationError extends Error { this.functionErrorStack.forEach(failingFunction => { if ( failingFunction.contractAddress.equals(contractAddress) && + failingFunction.functionSelector != null && failingFunction.functionSelector.equals(functionSelector) ) { failingFunction.functionName = functionName; @@ -175,7 +176,7 @@ export class SimulationError extends Error { const stackLines: string[] = [ ...functionCallStack.map(failingFunction => { return `at ${failingFunction.contractName ?? failingFunction.contractAddress.toString()}.${ - failingFunction.functionName ?? failingFunction.functionSelector.toString() + failingFunction.functionName ?? failingFunction.functionSelector?.toString() ?? '' }`; }), ...noirCallStack.map(errorLocation => diff --git a/yarn-project/pxe/src/pxe_service/error_enriching.ts b/yarn-project/pxe/src/pxe_service/error_enriching.ts index f9c26ba876ed..1ff72c04ba72 100644 --- a/yarn-project/pxe/src/pxe_service/error_enriching.ts +++ b/yarn-project/pxe/src/pxe_service/error_enriching.ts @@ -20,7 +20,7 @@ export async function enrichSimulationError(err: SimulationError, db: PxeDatabas if (!mentionedFunctions.has(contractAddress.toString())) { mentionedFunctions.set(contractAddress.toString(), new Set()); } - mentionedFunctions.get(contractAddress.toString())!.add(functionSelector.toString()); + mentionedFunctions.get(contractAddress.toString())!.add(functionSelector?.toString() ?? ''); }); await Promise.all( @@ -89,7 +89,9 @@ export async function enrichPublicSimulationError( err.setNoirCallStack(parsedCallStack); } catch (err) { logger.warn( - `Could not resolve noir call stack for ${originalFailingFunction.contractAddress.toString()}:${originalFailingFunction.functionSelector.toString()}: ${err}`, + `Could not resolve noir call stack for ${originalFailingFunction.contractAddress.toString()}:${ + originalFailingFunction.functionName?.toString() ?? '' + }: ${err}`, ); } } diff --git a/yarn-project/simulator/src/avm/avm_context.test.ts b/yarn-project/simulator/src/avm/avm_context.test.ts index 573adcb7eb13..ed8de8b74b08 100644 --- a/yarn-project/simulator/src/avm/avm_context.test.ts +++ b/yarn-project/simulator/src/avm/avm_context.test.ts @@ -10,7 +10,13 @@ describe('Avm Context', () => { const newAddress = AztecAddress.random(); const newCalldata = [new Fr(1), new Fr(2)]; const allocatedGas = { l2Gas: 2, daGas: 3 }; // How much of the current call gas we pass to the nested call - const newContext = context.createNestedContractCallContext(newAddress, newCalldata, allocatedGas, 'CALL'); + const newContext = context.createNestedContractCallContext( + newAddress, + newCalldata, + allocatedGas, + 'CALL', + 'top level function', + ); expect(newContext.environment).toEqual( allSameExcept(context.environment, { @@ -39,7 +45,13 @@ describe('Avm Context', () => { const newAddress = AztecAddress.random(); const newCalldata = [new Fr(1), new Fr(2)]; const allocatedGas = { l2Gas: 2, daGas: 3 }; - const newContext = context.createNestedContractCallContext(newAddress, newCalldata, allocatedGas, 'STATICCALL'); + const newContext = context.createNestedContractCallContext( + newAddress, + newCalldata, + allocatedGas, + 'STATICCALL', + 'static func', + ); expect(newContext.environment).toEqual( allSameExcept(context.environment, { diff --git a/yarn-project/simulator/src/avm/avm_context.ts b/yarn-project/simulator/src/avm/avm_context.ts index 50f202399942..d1dc7c341ccd 100644 --- a/yarn-project/simulator/src/avm/avm_context.ts +++ b/yarn-project/simulator/src/avm/avm_context.ts @@ -1,4 +1,4 @@ -import { type AztecAddress, FunctionSelector } from '@aztec/circuits.js'; +import { type AztecAddress } from '@aztec/circuits.js'; import { type Fr } from '@aztec/foundation/fields'; import { type AvmExecutionEnvironment } from './avm_execution_environment.js'; @@ -16,6 +16,7 @@ export class AvmContext { * @param persistableState - Manages world state and accrued substate during execution - (caching, fetching, tracing) * @param environment - Contains constant variables provided by the kernel * @param machineState - VM state that is modified on an instruction-by-instruction basis + * @param fnName - The function name which initiated this context. * @returns new AvmContext instance */ constructor( @@ -43,13 +44,13 @@ export class AvmContext { calldata: Fr[], allocatedGas: Gas, callType: 'CALL' | 'STATICCALL', - functionSelector: FunctionSelector = FunctionSelector.empty(), + fnName: string, ): AvmContext { const deriveFn = callType === 'CALL' ? this.environment.deriveEnvironmentForNestedCall : this.environment.deriveEnvironmentForNestedStaticCall; - const newExecutionEnvironment = deriveFn.call(this.environment, address, calldata, functionSelector); + const newExecutionEnvironment = deriveFn.call(this.environment, address, calldata, fnName); const forkedWorldState = this.persistableState.fork(); const machineState = AvmMachineState.fromState(gasToGasLeft(allocatedGas)); return new AvmContext(forkedWorldState, newExecutionEnvironment, machineState); diff --git a/yarn-project/simulator/src/avm/avm_execution_environment.test.ts b/yarn-project/simulator/src/avm/avm_execution_environment.test.ts index cadbfc5a33a3..f013a5f8dcd5 100644 --- a/yarn-project/simulator/src/avm/avm_execution_environment.test.ts +++ b/yarn-project/simulator/src/avm/avm_execution_environment.test.ts @@ -1,4 +1,4 @@ -import { AztecAddress, FunctionSelector } from '@aztec/circuits.js'; +import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { allSameExcept, initExecutionEnvironment } from './fixtures/index.js'; @@ -6,11 +6,10 @@ import { allSameExcept, initExecutionEnvironment } from './fixtures/index.js'; describe('Execution Environment', () => { const newAddress = AztecAddress.fromNumber(123456); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - const selector = FunctionSelector.empty(); it('New call should fork execution environment correctly', () => { const executionEnvironment = initExecutionEnvironment(); - const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedCall(newAddress, calldata, selector); + const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedCall(newAddress, calldata, 'func'); expect(newExecutionEnvironment).toEqual( allSameExcept(executionEnvironment, { @@ -26,7 +25,7 @@ describe('Execution Environment', () => { const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedStaticCall( newAddress, calldata, - selector, + 'static func', ); expect(newExecutionEnvironment).toEqual( diff --git a/yarn-project/simulator/src/avm/avm_execution_environment.ts b/yarn-project/simulator/src/avm/avm_execution_environment.ts index d4ebe69608b2..378ee49f4cb2 100644 --- a/yarn-project/simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/simulator/src/avm/avm_execution_environment.ts @@ -1,4 +1,4 @@ -import { FunctionSelector, type GlobalVariables } from '@aztec/circuits.js'; +import { type GlobalVariables } from '@aztec/circuits.js'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; @@ -10,7 +10,7 @@ export class AvmExecutionEnvironment { constructor( public readonly address: AztecAddress, public readonly sender: AztecAddress, - public readonly functionSelector: FunctionSelector, // may be temporary (#7224) + public readonly fnName: string, public readonly contractCallDepth: Fr, public readonly transactionFee: Fr, public readonly globals: GlobalVariables, @@ -21,13 +21,13 @@ export class AvmExecutionEnvironment { private deriveEnvironmentForNestedCallInternal( targetAddress: AztecAddress, calldata: Fr[], - functionSelector: FunctionSelector, + fnName: string, isStaticCall: boolean, ) { return new AvmExecutionEnvironment( /*address=*/ targetAddress, /*sender=*/ this.address, - functionSelector, + fnName, this.contractCallDepth.add(Fr.ONE), this.transactionFee, this.globals, @@ -39,26 +39,16 @@ export class AvmExecutionEnvironment { public deriveEnvironmentForNestedCall( targetAddress: AztecAddress, calldata: Fr[], - functionSelector: FunctionSelector = FunctionSelector.empty(), + fnName: string, ): AvmExecutionEnvironment { - return this.deriveEnvironmentForNestedCallInternal( - targetAddress, - calldata, - functionSelector, - /*isStaticCall=*/ false, - ); + return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, fnName, /*isStaticCall=*/ false); } public deriveEnvironmentForNestedStaticCall( targetAddress: AztecAddress, calldata: Fr[], - functionSelector: FunctionSelector, + fnName: string, ): AvmExecutionEnvironment { - return this.deriveEnvironmentForNestedCallInternal( - targetAddress, - calldata, - functionSelector, - /*isStaticCall=*/ true, - ); + return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, fnName, /*isStaticCall=*/ true); } } diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index ef06934d7c54..8770a389c8df 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -160,7 +160,6 @@ describe('AVM simulator: transpiled Noir contracts', () => { const ephemeralTrees = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface()); const persistableState = initPersistableStateManager({ worldStateDB, trace, merkleTrees: ephemeralTrees }); const environment = initExecutionEnvironment({ - functionSelector, calldata, globals, address: contractInstance.address, @@ -434,7 +433,6 @@ describe('AVM simulator: transpiled Noir contracts', () => { describe('Environment getters', () => { const address = AztecAddress.random(); const sender = AztecAddress.random(); - const functionSelector = FunctionSelector.random(); const transactionFee = Fr.random(); const chainId = Fr.random(); const version = Fr.random(); @@ -453,7 +451,6 @@ describe('AVM simulator: transpiled Noir contracts', () => { const env = initExecutionEnvironment({ address, sender, - functionSelector, transactionFee, globals, }); diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts index 480d668959f9..ca150f4690d0 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -1,10 +1,4 @@ -import { - type AztecAddress, - Fr, - type FunctionSelector, - type GlobalVariables, - MAX_L2_GAS_PER_ENQUEUED_CALL, -} from '@aztec/circuits.js'; +import { type AztecAddress, Fr, type GlobalVariables, MAX_L2_GAS_PER_ENQUEUED_CALL } from '@aztec/circuits.js'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { strict as assert } from 'assert'; @@ -54,7 +48,7 @@ export class AvmSimulator { context.machineState.gasLeft.l2Gas <= MAX_L2_GAS_PER_ENQUEUED_CALL, `Cannot allocate more than ${MAX_L2_GAS_PER_ENQUEUED_CALL} to the AVM for execution of an enqueued call`, ); - this.log = createDebugLogger(`aztec:avm_simulator:core(f:${context.environment.functionSelector.toString()})`); + this.log = createDebugLogger(`aztec:avm_simulator:core(f:${this.context.environment.fnName})`); // TODO(palla/log): Should tallies be printed on debug, or only on trace? if (this.log.isLevelEnabled('debug')) { this.tallyPrintFunction = this.printOpcodeTallies; @@ -65,8 +59,8 @@ export class AvmSimulator { public static create( stateManager: AvmPersistableStateManager, address: AztecAddress, + fnName: string, sender: AztecAddress, - functionSelector: FunctionSelector, // may be temporary (#7224) transactionFee: Fr, globals: GlobalVariables, isStaticCall: boolean, @@ -76,7 +70,7 @@ export class AvmSimulator { const avmExecutionEnv = new AvmExecutionEnvironment( address, sender, - functionSelector, + fnName, /*contractCallDepth=*/ Fr.zero(), transactionFee, globals, @@ -102,7 +96,7 @@ export class AvmSimulator { message, /*failingFunction=*/ { contractAddress: this.context.environment.address, - functionSelector: this.context.environment.functionSelector, + functionName: this.context.environment.fnName, }, /*noirCallStack=*/ [], ); diff --git a/yarn-project/simulator/src/avm/errors.ts b/yarn-project/simulator/src/avm/errors.ts index a147aefe922a..58c4974cc013 100644 --- a/yarn-project/simulator/src/avm/errors.ts +++ b/yarn-project/simulator/src/avm/errors.ts @@ -1,5 +1,5 @@ import { type FailingFunction, type NoirCallStack } from '@aztec/circuit-types'; -import { type AztecAddress, Fr, FunctionSelector, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js'; +import { type AztecAddress, type Fr } from '@aztec/circuits.js'; import { ExecutionError } from '../common/errors.js'; import { type AvmContext } from './avm_context.js'; @@ -139,15 +139,8 @@ export class AvmRevertReason extends ExecutionError { } function createRevertReason(message: string, revertData: Fr[], context: AvmContext): AvmRevertReason { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8985): Properly fix this. - // If the function selector is the public dispatch selector, we need to extract the actual function selector from the calldata. - // We should remove this because the AVM (or public protocol) shouldn't be aware of the public dispatch calling convention. - let functionSelector = context.environment.functionSelector; // We drop the returnPc information. const internalCallStack = context.machineState.internalCallStack.map(entry => entry.callPc); - if (functionSelector.toField().equals(new Fr(PUBLIC_DISPATCH_SELECTOR)) && context.environment.calldata.length > 0) { - functionSelector = FunctionSelector.fromField(context.environment.calldata[0]); - } // If we are reverting due to the same error that we have been tracking, we use the nested error as the cause. let nestedError = undefined; @@ -164,7 +157,7 @@ function createRevertReason(message: string, revertData: Fr[], context: AvmConte message, /*failingFunction=*/ { contractAddress: context.environment.address, - functionSelector: functionSelector, + functionName: context.environment.fnName, }, /*noirCallStack=*/ [...internalCallStack, context.machineState.pc].map(pc => `0.${pc}`), /*options=*/ { cause: nestedError }, diff --git a/yarn-project/simulator/src/avm/fixtures/index.ts b/yarn-project/simulator/src/avm/fixtures/index.ts index 5711c9d9dc68..ff23dbd3fe7c 100644 --- a/yarn-project/simulator/src/avm/fixtures/index.ts +++ b/yarn-project/simulator/src/avm/fixtures/index.ts @@ -64,7 +64,7 @@ export function initExecutionEnvironment(overrides?: Partial { + return await getPublicFunctionDebugName(this.worldStateDB, contractAddress, calldata); + } } function contractAddressIsCanonical(contractAddress: AztecAddress): boolean { diff --git a/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts b/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts index cd7c8fafab0d..1ec8e0e01757 100644 --- a/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts @@ -1,5 +1,4 @@ import { GasFees } from '@aztec/circuits.js'; -import { FunctionSelector as FunctionSelectorType } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; @@ -14,7 +13,6 @@ import { EnvironmentVariable, GetEnvVar } from './environment_getters.js'; describe('Environment getters', () => { const address = AztecAddress.random(); const sender = AztecAddress.random(); - const functionSelector = FunctionSelectorType.random(); const transactionFee = Fr.random(); const chainId = Fr.random(); const version = Fr.random(); @@ -34,7 +32,6 @@ describe('Environment getters', () => { const env = initExecutionEnvironment({ address, sender, - functionSelector, transactionFee, globals, isStaticCall, diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.ts index a5cb97ebc57d..4ed19d08a8d7 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.ts @@ -1,4 +1,4 @@ -import { Fr, FunctionSelector, Gas, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js'; +import { Gas } from '@aztec/circuits.js'; import type { AvmContext } from '../avm_context.js'; import { type AvmContractCallResult } from '../avm_contract_call_result.js'; @@ -45,7 +45,6 @@ abstract class ExternalCall extends Instruction { const callAddress = memory.getAs(addrOffset); const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr()); - const functionSelector = new Fr(PUBLIC_DISPATCH_SELECTOR); // If we are already in a static call, we propagate the environment. const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type; @@ -62,12 +61,15 @@ abstract class ExternalCall extends Instruction { const allocatedGas = { l2Gas: allocatedL2Gas, daGas: allocatedDaGas }; context.machineState.consumeGas(allocatedGas); + const aztecAddress = callAddress.toAztecAddress(); + const fnName = await context.persistableState.getPublicFunctionDebugName(aztecAddress, calldata); + const nestedContext = context.createNestedContractCallContext( - callAddress.toAztecAddress(), + aztecAddress, calldata, allocatedGas, callType, - FunctionSelector.fromField(functionSelector), + fnName, ); const simulator = new AvmSimulator(nestedContext); diff --git a/yarn-project/simulator/src/common/debug_fn_name.ts b/yarn-project/simulator/src/common/debug_fn_name.ts index b8d9647d6b76..aba0827b011f 100644 --- a/yarn-project/simulator/src/common/debug_fn_name.ts +++ b/yarn-project/simulator/src/common/debug_fn_name.ts @@ -1,22 +1,16 @@ -import { type AztecAddress, Fr, FunctionSelector, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js'; +import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js'; import { type WorldStateDB } from '../public/public_db_sources.js'; export async function getPublicFunctionDebugName( db: WorldStateDB, contractAddress: AztecAddress, - fn: FunctionSelector, calldata: Fr[], ): Promise { - if (fn.equals(FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)))) { - // If the function is a dispatch, we need to look up the target function which - // is expected to be the first argument. - const targetFunction = - calldata[0] !== undefined - ? await db.getDebugFunctionName(contractAddress, FunctionSelector.fromField(calldata[0])) - : ``; - return `${targetFunction} (via dispatch)`; - } else { - return (await db.getDebugFunctionName(contractAddress, fn)) ?? `${contractAddress}:${fn}`; - } + // Public function is dispatched and therefore the target function is passed in the first argument. + const targetFunction = + calldata[0] !== undefined + ? await db.getDebugFunctionName(contractAddress, FunctionSelector.fromField(calldata[0])) + : ` (Contract Address: ${contractAddress})`; + return `${targetFunction} (via dispatch)`; } diff --git a/yarn-project/simulator/src/public/public_tx_simulator.ts b/yarn-project/simulator/src/public/public_tx_simulator.ts index 3fd7afd59056..6b517a8ed4ae 100644 --- a/yarn-project/simulator/src/public/public_tx_simulator.ts +++ b/yarn-project/simulator/src/public/public_tx_simulator.ts @@ -264,8 +264,7 @@ export class PublicTxSimulator { ): Promise { const stateManager = context.state.getActiveStateManager(); const address = executionRequest.callContext.contractAddress; - const selector = executionRequest.callContext.functionSelector; - const fnName = await getPublicFunctionDebugName(this.worldStateDB, address, selector, executionRequest.args); + const fnName = await getPublicFunctionDebugName(this.worldStateDB, address, executionRequest.args); const availableGas = context.getGasLeftForPhase(phase); // Gas allocated to an enqueued call can be different from the available gas @@ -328,7 +327,6 @@ export class PublicTxSimulator { ): Promise { const address = executionRequest.callContext.contractAddress; const sender = executionRequest.callContext.msgSender; - const selector = executionRequest.callContext.functionSelector; this.log.verbose( `[AVM] Executing enqueued public call to external function ${fnName}@${address} with ${allocatedGas.l2Gas} allocated L2 gas.`, @@ -338,8 +336,8 @@ export class PublicTxSimulator { const simulator = AvmSimulator.create( stateManager, address, + fnName, sender, - selector, transactionFee, this.globalVariables, executionRequest.callContext.isStaticCall, diff --git a/yarn-project/simulator/src/public/side_effect_trace.ts b/yarn-project/simulator/src/public/side_effect_trace.ts index bb7e48791cda..47233e2147d6 100644 --- a/yarn-project/simulator/src/public/side_effect_trace.ts +++ b/yarn-project/simulator/src/public/side_effect_trace.ts @@ -17,6 +17,7 @@ import { ContractStorageRead, ContractStorageUpdateRequest, EthAddress, + FunctionSelector, Gas, L1_TO_L2_MSG_TREE_HEIGHT, L2ToL1Message, @@ -535,7 +536,7 @@ function createPublicExecutionRequest(avmEnvironment: AvmExecutionEnvironment): const callContext = CallContext.from({ msgSender: avmEnvironment.sender, contractAddress: avmEnvironment.address, - functionSelector: avmEnvironment.functionSelector, + functionSelector: FunctionSelector.empty(), isStaticCall: avmEnvironment.isStaticCall, }); return new PublicExecutionRequest(callContext, avmEnvironment.calldata);