Skip to content

Commit

Permalink
feat: Add a flag to disable fee payment checks in AVM simulator (#10852)
Browse files Browse the repository at this point in the history
Resolves #10833
This is a simulator only change, since the AVM circuit should keep
failing if the balance is not enough.
  • Loading branch information
sirasistant authored Dec 19, 2024
1 parent 3d00d34 commit 41407ce
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 56 deletions.
4 changes: 2 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ export class AztecNodeService implements AztecNode, Traceable {
@trackSpan('AztecNodeService.simulatePublicCalls', (tx: Tx) => ({
[Attributes.TX_HASH]: tx.tryGetTxHash()?.toString(),
}))
public async simulatePublicCalls(tx: Tx): Promise<PublicSimulationOutput> {
public async simulatePublicCalls(tx: Tx, enforceFeePayment = true): Promise<PublicSimulationOutput> {
const txHash = tx.getTxHash();
const blockNumber = (await this.blockSource.getBlockNumber()) + 1;

Expand All @@ -825,7 +825,7 @@ export class AztecNodeService implements AztecNode, Traceable {
});

try {
const processor = publicProcessorFactory.create(fork, prevHeader, newGlobalVariables);
const processor = publicProcessorFactory.create(fork, prevHeader, newGlobalVariables, enforceFeePayment);

// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
const [processedTxs, failedTxs, returns] = await processor.process([tx]);
Expand Down
16 changes: 14 additions & 2 deletions yarn-project/aztec.js/src/contract/base_contract_interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ export abstract class BaseContractInteraction {
opts?: Omit<SendMethodOptions, 'estimateGas' | 'skipPublicSimulation'>,
): Promise<Pick<GasSettings, 'gasLimits' | 'teardownGasLimits'>> {
const txRequest = await this.create({ ...opts, fee: { ...opts?.fee, estimateGas: false } });
const simulationResult = await this.wallet.simulateTx(txRequest, true);
const simulationResult = await this.wallet.simulateTx(
txRequest,
true /*simulatePublic*/,
undefined /* msgSender */,
undefined /* skipTxValidation */,
false /* enforceFeePayment */,
);
const { totalGas: gasLimits, teardownGas: teardownGasLimits } = getGasLimits(
simulationResult,
opts?.fee?.estimatedGasPadding,
Expand Down Expand Up @@ -128,7 +134,13 @@ export abstract class BaseContractInteraction {
if (request.fee?.estimateGas) {
const feeForEstimation: FeeOptions = { paymentMethod, gasSettings };
const txRequest = await this.wallet.createTxExecutionRequest({ ...request, fee: feeForEstimation });
const simulationResult = await this.wallet.simulateTx(txRequest, true);
const simulationResult = await this.wallet.simulateTx(
txRequest,
true /*simulatePublic*/,
undefined /* msgSender */,
undefined /* skipTxValidation */,
false /* enforceFeePayment */,
);
const { totalGas: gasLimits, teardownGas: teardownGasLimits } = getGasLimits(
simulationResult,
request.fee?.estimatedGasPadding,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,14 @@ export class ContractFunctionInteraction extends BaseContractInteraction {
}

const txRequest = await this.create();
const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from, options?.skipTxValidation, true);
const simulatedTx = await this.wallet.simulateTx(
txRequest,
true,
options?.from,
options?.skipTxValidation,
undefined,
true,
);

const rawReturnValues =
this.functionDao.functionType == FunctionType.PRIVATE
Expand Down
11 changes: 10 additions & 1 deletion yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,18 @@ export abstract class BaseWallet implements Wallet {
simulatePublic: boolean,
msgSender?: AztecAddress,
skipTxValidation?: boolean,
enforceFeePayment?: boolean,
profile?: boolean,
): Promise<TxSimulationResult> {
return this.pxe.simulateTx(txRequest, simulatePublic, msgSender, skipTxValidation, profile, this.scopes);
return this.pxe.simulateTx(
txRequest,
simulatePublic,
msgSender,
skipTxValidation,
enforceFeePayment,
profile,
this.scopes,
);
}
sendTx(tx: Tx): Promise<TxHash> {
return this.pxe.sendTx(tx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ class MockAztecNode implements AztecNode {
getBlockHeader(_blockNumber?: number | 'latest' | undefined): Promise<BlockHeader> {
return Promise.resolve(BlockHeader.empty());
}
simulatePublicCalls(tx: Tx): Promise<PublicSimulationOutput> {
simulatePublicCalls(tx: Tx, _enforceFeePayment = false): Promise<PublicSimulationOutput> {
expect(tx).toBeInstanceOf(Tx);
return Promise.resolve(PublicSimulationOutput.random());
}
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/circuit-types/src/interfaces/aztec-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ export interface AztecNode
* This currently just checks that the transaction execution succeeds.
* @param tx - The transaction to simulate.
**/
simulatePublicCalls(tx: Tx): Promise<PublicSimulationOutput>;
simulatePublicCalls(tx: Tx, enforceFeePayment?: boolean): Promise<PublicSimulationOutput>;

/**
* Returns true if the transaction is valid for inclusion at the current state. Valid transactions can be
Expand Down Expand Up @@ -565,7 +565,7 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {

getBlockHeader: z.function().args(optional(L2BlockNumberSchema)).returns(BlockHeader.schema),

simulatePublicCalls: z.function().args(Tx.schema).returns(PublicSimulationOutput.schema),
simulatePublicCalls: z.function().args(Tx.schema, optional(z.boolean())).returns(PublicSimulationOutput.schema),

isValidTx: z.function().args(Tx.schema, optional(z.boolean())).returns(z.boolean()),

Expand Down
4 changes: 3 additions & 1 deletion yarn-project/circuit-types/src/interfaces/pxe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ describe('PXESchema', () => {
});

it('simulateTx(all)', async () => {
const result = await context.client.simulateTx(TxExecutionRequest.random(), true, address, false, false, []);
const result = await context.client.simulateTx(TxExecutionRequest.random(), true, address, false, true, false, []);
expect(result).toBeInstanceOf(TxSimulationResult);
});

Expand All @@ -168,6 +168,7 @@ describe('PXESchema', () => {
undefined,
undefined,
undefined,
undefined,
);
expect(result).toBeInstanceOf(TxSimulationResult);
});
Expand Down Expand Up @@ -381,6 +382,7 @@ class MockPXE implements PXE {
_simulatePublic: boolean,
msgSender?: AztecAddress | undefined,
_skipTxValidation?: boolean | undefined,
_enforceFeePayment?: boolean | undefined,
_profile?: boolean | undefined,
scopes?: AztecAddress[] | undefined,
): Promise<TxSimulationResult> {
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export interface PXE {
simulatePublic: boolean,
msgSender?: AztecAddress,
skipTxValidation?: boolean,
enforceFeePayment?: boolean,
profile?: boolean,
scopes?: AztecAddress[],
): Promise<TxSimulationResult>;
Expand Down Expand Up @@ -484,6 +485,7 @@ export const PXESchema: ApiSchemaFor<PXE> = {
optional(schemas.AztecAddress),
optional(z.boolean()),
optional(z.boolean()),
optional(z.boolean()),
optional(z.array(schemas.AztecAddress)),
)
.returns(TxSimulationResult.schema),
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/prover-node/src/job/epoch-proving-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class EpochProvingJob implements Traceable {

// Process public fns
const db = await this.dbProvider.fork(block.number - 1);
const publicProcessor = this.publicProcessorFactory.create(db, previousHeader, globalVariables);
const publicProcessor = this.publicProcessorFactory.create(db, previousHeader, globalVariables, true);
const processed = await this.processTxs(publicProcessor, txs, txCount);
await this.prover.addTxs(processed);
await db.close();
Expand Down
7 changes: 4 additions & 3 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ export class PXEService implements PXE {
simulatePublic: boolean,
msgSender: AztecAddress | undefined = undefined,
skipTxValidation: boolean = false,
enforceFeePayment: boolean = true,
profile: boolean = false,
scopes?: AztecAddress[],
): Promise<TxSimulationResult> {
Expand Down Expand Up @@ -523,7 +524,7 @@ export class PXEService implements PXE {
const simulatedTx = privateSimulationResult.toSimulatedTx();
let publicOutput: PublicSimulationOutput | undefined;
if (simulatePublic) {
publicOutput = await this.#simulatePublicCalls(simulatedTx);
publicOutput = await this.#simulatePublicCalls(simulatedTx, enforceFeePayment);
}

if (!skipTxValidation) {
Expand Down Expand Up @@ -780,11 +781,11 @@ export class PXEService implements PXE {
* It can also be used for estimating gas in the future.
* @param tx - The transaction to be simulated.
*/
async #simulatePublicCalls(tx: Tx) {
async #simulatePublicCalls(tx: Tx, enforceFeePayment: boolean) {
// Simulating public calls can throw if the TX fails in a phase that doesn't allow reverts (setup)
// Or return as reverted if it fails in a phase that allows reverts (app logic, teardown)
try {
const result = await this.node.simulatePublicCalls(tx);
const result = await this.node.simulatePublicCalls(tx, enforceFeePayment);
if (result.revertReason) {
throw result.revertReason;
}
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,12 @@ export class Sequencer {
const orchestratorFork = await this.worldState.fork();

try {
const processor = this.publicProcessorFactory.create(publicProcessorFork, historicalHeader, newGlobalVariables);
const processor = this.publicProcessorFactory.create(
publicProcessorFork,
historicalHeader,
newGlobalVariables,
true,
);
const blockBuildingTimer = new Timer();
const blockBuilder = this.blockBuilderFactory.create(orchestratorFork);
await blockBuilder.startNewBlock(newGlobalVariables, l1ToL2Messages);
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/simulator/src/public/public_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ export class PublicProcessorFactory {
* Creates a new instance of a PublicProcessor.
* @param historicalHeader - The header of a block previous to the one in which the tx is included.
* @param globalVariables - The global variables for the block being processed.
* @param enforceFeePayment - Allows disabling balance checks for fee estimations.
* @returns A new instance of a PublicProcessor.
*/
public create(
merkleTree: MerkleTreeWriteOperations,
maybeHistoricalHeader: BlockHeader | undefined,
globalVariables: GlobalVariables,
enforceFeePayment: boolean,
): PublicProcessor {
const historicalHeader = maybeHistoricalHeader ?? merkleTree.getInitialHeader();

Expand All @@ -59,6 +61,7 @@ export class PublicProcessorFactory {
this.telemetryClient,
globalVariables,
/*doMerkleOperations=*/ true,
enforceFeePayment,
);

return new PublicProcessor(
Expand Down
Loading

0 comments on commit 41407ce

Please sign in to comment.