Skip to content

Commit fef5f93

Browse files
authored
chore(avm): Remove function selector from AvmExecutionEnvironment (#10532)
1 parent 49f9418 commit fef5f93

15 files changed

+70
-114
lines changed

yarn-project/circuit-types/src/simulation_error.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface FailingFunction {
1919
/**
2020
* The selector of the function that failed.
2121
*/
22-
functionSelector: FunctionSelector;
22+
functionSelector?: FunctionSelector;
2323
/**
2424
* The name of the function that failed.
2525
*/
@@ -160,6 +160,7 @@ export class SimulationError extends Error {
160160
this.functionErrorStack.forEach(failingFunction => {
161161
if (
162162
failingFunction.contractAddress.equals(contractAddress) &&
163+
!!failingFunction.functionSelector &&
163164
failingFunction.functionSelector.equals(functionSelector)
164165
) {
165166
failingFunction.functionName = functionName;
@@ -175,7 +176,7 @@ export class SimulationError extends Error {
175176
const stackLines: string[] = [
176177
...functionCallStack.map(failingFunction => {
177178
return `at ${failingFunction.contractName ?? failingFunction.contractAddress.toString()}.${
178-
failingFunction.functionName ?? failingFunction.functionSelector.toString()
179+
failingFunction.functionName ?? failingFunction.functionSelector?.toString() ?? 'unknown'
179180
}`;
180181
}),
181182
...noirCallStack.map(errorLocation =>

yarn-project/pxe/src/pxe_service/error_enriching.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function enrichSimulationError(err: SimulationError, db: PxeDatabas
2020
if (!mentionedFunctions.has(contractAddress.toString())) {
2121
mentionedFunctions.set(contractAddress.toString(), new Set());
2222
}
23-
mentionedFunctions.get(contractAddress.toString())!.add(functionSelector.toString());
23+
mentionedFunctions.get(contractAddress.toString())!.add(functionSelector?.toString() ?? '');
2424
});
2525

2626
await Promise.all(
@@ -89,7 +89,9 @@ export async function enrichPublicSimulationError(
8989
err.setNoirCallStack(parsedCallStack);
9090
} catch (err) {
9191
logger.warn(
92-
`Could not resolve noir call stack for ${originalFailingFunction.contractAddress.toString()}:${originalFailingFunction.functionSelector.toString()}: ${err}`,
92+
`Could not resolve noir call stack for ${originalFailingFunction.contractAddress.toString()}:${
93+
originalFailingFunction.functionName?.toString() ?? ''
94+
}: ${err}`,
9395
);
9496
}
9597
}

yarn-project/simulator/src/avm/avm_context.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type AztecAddress, FunctionSelector } from '@aztec/circuits.js';
1+
import { type AztecAddress } from '@aztec/circuits.js';
22
import { type Fr } from '@aztec/foundation/fields';
33

44
import { type AvmExecutionEnvironment } from './avm_execution_environment.js';
@@ -43,13 +43,12 @@ export class AvmContext {
4343
calldata: Fr[],
4444
allocatedGas: Gas,
4545
callType: 'CALL' | 'STATICCALL',
46-
functionSelector: FunctionSelector = FunctionSelector.empty(),
4746
): AvmContext {
4847
const deriveFn =
4948
callType === 'CALL'
5049
? this.environment.deriveEnvironmentForNestedCall
5150
: this.environment.deriveEnvironmentForNestedStaticCall;
52-
const newExecutionEnvironment = deriveFn.call(this.environment, address, calldata, functionSelector);
51+
const newExecutionEnvironment = deriveFn.call(this.environment, address, calldata);
5352
const forkedWorldState = this.persistableState.fork();
5453
const machineState = AvmMachineState.fromState(gasToGasLeft(allocatedGas));
5554
return new AvmContext(forkedWorldState, newExecutionEnvironment, machineState);

yarn-project/simulator/src/avm/avm_execution_environment.test.ts

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
import { AztecAddress, FunctionSelector } from '@aztec/circuits.js';
1+
import { AztecAddress } from '@aztec/circuits.js';
22
import { Fr } from '@aztec/foundation/fields';
33

44
import { allSameExcept, initExecutionEnvironment } from './fixtures/index.js';
55

66
describe('Execution Environment', () => {
77
const newAddress = AztecAddress.fromNumber(123456);
88
const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)];
9-
const selector = FunctionSelector.empty();
109

1110
it('New call should fork execution environment correctly', () => {
1211
const executionEnvironment = initExecutionEnvironment();
13-
const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedCall(newAddress, calldata, selector);
12+
const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedCall(newAddress, calldata);
1413

1514
expect(newExecutionEnvironment).toEqual(
1615
allSameExcept(executionEnvironment, {
@@ -21,13 +20,9 @@ describe('Execution Environment', () => {
2120
);
2221
});
2322

24-
it('New static call call should fork execution environment correctly', () => {
23+
it('New static call should fork execution environment correctly', () => {
2524
const executionEnvironment = initExecutionEnvironment();
26-
const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedStaticCall(
27-
newAddress,
28-
calldata,
29-
selector,
30-
);
25+
const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedStaticCall(newAddress, calldata);
3126

3227
expect(newExecutionEnvironment).toEqual(
3328
allSameExcept(executionEnvironment, {
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FunctionSelector, type GlobalVariables } from '@aztec/circuits.js';
1+
import { type GlobalVariables } from '@aztec/circuits.js';
22
import { type AztecAddress } from '@aztec/foundation/aztec-address';
33
import { Fr } from '@aztec/foundation/fields';
44

@@ -10,24 +10,17 @@ export class AvmExecutionEnvironment {
1010
constructor(
1111
public readonly address: AztecAddress,
1212
public readonly sender: AztecAddress,
13-
public readonly functionSelector: FunctionSelector, // may be temporary (#7224)
1413
public readonly contractCallDepth: Fr,
1514
public readonly transactionFee: Fr,
1615
public readonly globals: GlobalVariables,
1716
public readonly isStaticCall: boolean,
1817
public readonly calldata: Fr[],
1918
) {}
2019

21-
private deriveEnvironmentForNestedCallInternal(
22-
targetAddress: AztecAddress,
23-
calldata: Fr[],
24-
functionSelector: FunctionSelector,
25-
isStaticCall: boolean,
26-
) {
20+
private deriveEnvironmentForNestedCallInternal(targetAddress: AztecAddress, calldata: Fr[], isStaticCall: boolean) {
2721
return new AvmExecutionEnvironment(
2822
/*address=*/ targetAddress,
2923
/*sender=*/ this.address,
30-
functionSelector,
3124
this.contractCallDepth.add(Fr.ONE),
3225
this.transactionFee,
3326
this.globals,
@@ -36,29 +29,11 @@ export class AvmExecutionEnvironment {
3629
);
3730
}
3831

39-
public deriveEnvironmentForNestedCall(
40-
targetAddress: AztecAddress,
41-
calldata: Fr[],
42-
functionSelector: FunctionSelector = FunctionSelector.empty(),
43-
): AvmExecutionEnvironment {
44-
return this.deriveEnvironmentForNestedCallInternal(
45-
targetAddress,
46-
calldata,
47-
functionSelector,
48-
/*isStaticCall=*/ false,
49-
);
32+
public deriveEnvironmentForNestedCall(targetAddress: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment {
33+
return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, /*isStaticCall=*/ false);
5034
}
5135

52-
public deriveEnvironmentForNestedStaticCall(
53-
targetAddress: AztecAddress,
54-
calldata: Fr[],
55-
functionSelector: FunctionSelector,
56-
): AvmExecutionEnvironment {
57-
return this.deriveEnvironmentForNestedCallInternal(
58-
targetAddress,
59-
calldata,
60-
functionSelector,
61-
/*isStaticCall=*/ true,
62-
);
36+
public deriveEnvironmentForNestedStaticCall(targetAddress: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment {
37+
return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, /*isStaticCall=*/ true);
6338
}
6439
}

yarn-project/simulator/src/avm/avm_simulator.test.ts

-3
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ describe('AVM simulator: transpiled Noir contracts', () => {
160160
const ephemeralTrees = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
161161
const persistableState = initPersistableStateManager({ worldStateDB, trace, merkleTrees: ephemeralTrees });
162162
const environment = initExecutionEnvironment({
163-
functionSelector,
164163
calldata,
165164
globals,
166165
address: contractInstance.address,
@@ -434,7 +433,6 @@ describe('AVM simulator: transpiled Noir contracts', () => {
434433
describe('Environment getters', () => {
435434
const address = AztecAddress.random();
436435
const sender = AztecAddress.random();
437-
const functionSelector = FunctionSelector.random();
438436
const transactionFee = Fr.random();
439437
const chainId = Fr.random();
440438
const version = Fr.random();
@@ -453,7 +451,6 @@ describe('AVM simulator: transpiled Noir contracts', () => {
453451
const env = initExecutionEnvironment({
454452
address,
455453
sender,
456-
functionSelector,
457454
transactionFee,
458455
globals,
459456
});

yarn-project/simulator/src/avm/avm_simulator.ts

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import {
2-
type AztecAddress,
3-
Fr,
4-
type FunctionSelector,
5-
type GlobalVariables,
6-
MAX_L2_GAS_PER_ENQUEUED_CALL,
7-
} from '@aztec/circuits.js';
1+
import { type AztecAddress, Fr, type GlobalVariables, MAX_L2_GAS_PER_ENQUEUED_CALL } from '@aztec/circuits.js';
82
import { type Logger, createLogger } from '@aztec/foundation/log';
93

104
import { strict as assert } from 'assert';
@@ -49,24 +43,35 @@ export class AvmSimulator {
4943
private tallyPrintFunction = () => {};
5044
private tallyInstructionFunction = (_a: number, _b: string, _c: Gas) => {};
5145

46+
// Test Purposes only: Logger will not have the proper function name. Use this constructor for testing purposes
47+
// only. Otherwise, use build() below.
5248
constructor(private context: AvmContext, private instructionSet: InstructionSet = INSTRUCTION_SET()) {
5349
assert(
5450
context.machineState.gasLeft.l2Gas <= MAX_L2_GAS_PER_ENQUEUED_CALL,
5551
`Cannot allocate more than ${MAX_L2_GAS_PER_ENQUEUED_CALL} to the AVM for execution of an enqueued call`,
5652
);
57-
this.log = createLogger(`simulator:avm:core(f:${context.environment.functionSelector.toString()})`);
53+
this.log = createLogger(`simulator:avm(calldata[0]: ${context.environment.calldata[0]})`);
5854
// TODO(palla/log): Should tallies be printed on debug, or only on trace?
5955
if (this.log.isLevelEnabled('debug')) {
6056
this.tallyPrintFunction = this.printOpcodeTallies;
6157
this.tallyInstructionFunction = this.tallyInstruction;
6258
}
6359
}
6460

65-
public static create(
61+
// Factory to have a proper function name in the logger. Retrieving the name is asynchronous and
62+
// cannot be done as part of the constructor.
63+
public static async build(context: AvmContext): Promise<AvmSimulator> {
64+
const simulator = new AvmSimulator(context);
65+
const fnName = await context.persistableState.getPublicFunctionDebugName(context.environment);
66+
simulator.log = createLogger(`simulator:avm(f:${fnName})`);
67+
68+
return simulator;
69+
}
70+
71+
public static async create(
6672
stateManager: AvmPersistableStateManager,
6773
address: AztecAddress,
6874
sender: AztecAddress,
69-
functionSelector: FunctionSelector, // may be temporary (#7224)
7075
transactionFee: Fr,
7176
globals: GlobalVariables,
7277
isStaticCall: boolean,
@@ -76,7 +81,6 @@ export class AvmSimulator {
7681
const avmExecutionEnv = new AvmExecutionEnvironment(
7782
address,
7883
sender,
79-
functionSelector,
8084
/*contractCallDepth=*/ Fr.zero(),
8185
transactionFee,
8286
globals,
@@ -86,8 +90,7 @@ export class AvmSimulator {
8690

8791
const avmMachineState = new AvmMachineState(allocatedGas);
8892
const avmContext = new AvmContext(stateManager, avmExecutionEnv, avmMachineState);
89-
const instructionSet = INSTRUCTION_SET();
90-
return new AvmSimulator(avmContext, instructionSet);
93+
return await AvmSimulator.build(avmContext);
9194
}
9295

9396
/**
@@ -98,11 +101,12 @@ export class AvmSimulator {
98101
if (!bytecode) {
99102
// revert, consuming all gas
100103
const message = `No bytecode found at: ${this.context.environment.address}. Reverting...`;
104+
const fnName = await this.context.persistableState.getPublicFunctionDebugName(this.context.environment);
101105
const revertReason = new AvmRevertReason(
102106
message,
103107
/*failingFunction=*/ {
104108
contractAddress: this.context.environment.address,
105-
functionSelector: this.context.environment.functionSelector,
109+
functionName: fnName,
106110
},
107111
/*noirCallStack=*/ [],
108112
);
@@ -176,7 +180,7 @@ export class AvmSimulator {
176180

177181
const output = machineState.getOutput();
178182
const reverted = machineState.getReverted();
179-
const revertReason = reverted ? revertReasonFromExplicitRevert(output, this.context) : undefined;
183+
const revertReason = reverted ? await revertReasonFromExplicitRevert(output, this.context) : undefined;
180184
const results = new AvmContractCallResult(reverted, output, machineState.gasLeft, revertReason);
181185
this.log.debug(`Context execution results: ${results.toString()}`);
182186

@@ -190,7 +194,7 @@ export class AvmSimulator {
190194
throw err;
191195
}
192196

193-
const revertReason = revertReasonFromExceptionalHalt(err, this.context);
197+
const revertReason = await revertReasonFromExceptionalHalt(err, this.context);
194198
// Note: "exceptional halts" cannot return data, hence [].
195199
const results = new AvmContractCallResult(/*reverted=*/ true, /*output=*/ [], machineState.gasLeft, revertReason);
196200
this.log.debug(`Context execution results: ${results.toString()}`);

yarn-project/simulator/src/avm/errors.ts

+12-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type FailingFunction, type NoirCallStack } from '@aztec/circuit-types';
2-
import { type AztecAddress, Fr, FunctionSelector, PUBLIC_DISPATCH_SELECTOR } from '@aztec/circuits.js';
2+
import { type AztecAddress, type Fr } from '@aztec/circuits.js';
33

44
import { ExecutionError } from '../common/errors.js';
55
import { type AvmContext } from './avm_context.js';
@@ -138,16 +138,9 @@ export class AvmRevertReason extends ExecutionError {
138138
}
139139
}
140140

141-
function createRevertReason(message: string, revertData: Fr[], context: AvmContext): AvmRevertReason {
142-
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/8985): Properly fix this.
143-
// If the function selector is the public dispatch selector, we need to extract the actual function selector from the calldata.
144-
// We should remove this because the AVM (or public protocol) shouldn't be aware of the public dispatch calling convention.
145-
let functionSelector = context.environment.functionSelector;
141+
async function createRevertReason(message: string, revertData: Fr[], context: AvmContext): Promise<AvmRevertReason> {
146142
// We drop the returnPc information.
147143
const internalCallStack = context.machineState.internalCallStack.map(entry => entry.callPc);
148-
if (functionSelector.toField().equals(new Fr(PUBLIC_DISPATCH_SELECTOR)) && context.environment.calldata.length > 0) {
149-
functionSelector = FunctionSelector.fromField(context.environment.calldata[0]);
150-
}
151144

152145
// If we are reverting due to the same error that we have been tracking, we use the nested error as the cause.
153146
let nestedError = undefined;
@@ -160,11 +153,13 @@ function createRevertReason(message: string, revertData: Fr[], context: AvmConte
160153
message = context.machineState.collectedRevertInfo.recursiveRevertReason.message;
161154
}
162155

156+
const fnName = await context.persistableState.getPublicFunctionDebugName(context.environment);
157+
163158
return new AvmRevertReason(
164159
message,
165160
/*failingFunction=*/ {
166161
contractAddress: context.environment.address,
167-
functionSelector: functionSelector,
162+
functionName: fnName,
168163
},
169164
/*noirCallStack=*/ [...internalCallStack, context.machineState.pc].map(pc => `0.${pc}`),
170165
/*options=*/ { cause: nestedError },
@@ -177,8 +172,11 @@ function createRevertReason(message: string, revertData: Fr[], context: AvmConte
177172
* @param haltingError - the lower-level error causing the exceptional halt
178173
* @param context - the context of the AVM execution used to extract the failingFunction and noirCallStack
179174
*/
180-
export function revertReasonFromExceptionalHalt(haltingError: AvmExecutionError, context: AvmContext): AvmRevertReason {
181-
return createRevertReason(haltingError.message, [], context);
175+
export async function revertReasonFromExceptionalHalt(
176+
haltingError: AvmExecutionError,
177+
context: AvmContext,
178+
): Promise<AvmRevertReason> {
179+
return await createRevertReason(haltingError.message, [], context);
182180
}
183181

184182
/**
@@ -187,6 +185,6 @@ export function revertReasonFromExceptionalHalt(haltingError: AvmExecutionError,
187185
* @param revertData - output data of the explicit REVERT instruction
188186
* @param context - the context of the AVM execution used to extract the failingFunction and noirCallStack
189187
*/
190-
export function revertReasonFromExplicitRevert(revertData: Fr[], context: AvmContext): AvmRevertReason {
191-
return createRevertReason('Assertion failed: ', revertData, context);
188+
export async function revertReasonFromExplicitRevert(revertData: Fr[], context: AvmContext): Promise<AvmRevertReason> {
189+
return await createRevertReason('Assertion failed: ', revertData, context);
192190
}

yarn-project/simulator/src/avm/fixtures/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnviron
6464
return new AvmExecutionEnvironment(
6565
overrides?.address ?? AztecAddress.zero(),
6666
overrides?.sender ?? AztecAddress.zero(),
67-
overrides?.functionSelector ?? FunctionSelector.empty(),
6867
overrides?.contractCallDepth ?? Fr.zero(),
6968
overrides?.transactionFee ?? Fr.zero(),
7069
overrides?.globals ?? GlobalVariables.empty(),

yarn-project/simulator/src/avm/journal/journal.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,6 @@ export class AvmPersistableStateManager {
687687
const functionName = await getPublicFunctionDebugName(
688688
this.worldStateDB,
689689
nestedEnvironment.address,
690-
nestedEnvironment.functionSelector,
691690
nestedEnvironment.calldata,
692691
);
693692

@@ -706,6 +705,10 @@ export class AvmPersistableStateManager {
706705
public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
707706
this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
708707
}
708+
709+
public async getPublicFunctionDebugName(avmEnvironment: AvmExecutionEnvironment): Promise<string> {
710+
return await getPublicFunctionDebugName(this.worldStateDB, avmEnvironment.address, avmEnvironment.calldata);
711+
}
709712
}
710713

711714
function contractAddressIsCanonical(contractAddress: AztecAddress): boolean {

0 commit comments

Comments
 (0)