From 1c7c44742d0b3e6940ea08a42085d236fd209cad Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 2 Sep 2024 09:46:26 -0300 Subject: [PATCH] feat: Add bot config to toggle simulation (#8297) Allow turning off simulation and gas estimation on the bot via config. --- yarn-project/bot/src/bot.ts | 36 ++++++++++++++----- yarn-project/bot/src/config.ts | 22 ++++++++++++ yarn-project/end-to-end/src/e2e_bot.test.ts | 18 ++++++++-- yarn-project/foundation/src/config/env_var.ts | 3 ++ yarn-project/foundation/src/config/index.ts | 15 ++++++++ 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/yarn-project/bot/src/bot.ts b/yarn-project/bot/src/bot.ts index 9d154f44982..8685b32df39 100644 --- a/yarn-project/bot/src/bot.ts +++ b/yarn-project/bot/src/bot.ts @@ -8,7 +8,7 @@ import { createDebugLogger, } from '@aztec/aztec.js'; import { type AztecNode, type FunctionCall, type PXE } from '@aztec/circuit-types'; -import { GasSettings } from '@aztec/circuits.js'; +import { Gas, GasSettings } from '@aztec/circuits.js'; import { times } from '@aztec/foundation/collection'; import { type TokenContract } from '@aztec/noir-contracts.js'; @@ -25,7 +25,7 @@ export class Bot { public readonly wallet: Wallet, public readonly token: TokenContract, public readonly recipient: AztecAddress, - public readonly config: BotConfig, + public config: BotConfig, ) {} static async create(config: BotConfig, dependencies: { pxe?: PXE; node?: AztecNode } = {}): Promise { @@ -33,6 +33,11 @@ export class Bot { return new Bot(wallet, token, recipient, config); } + public updateConfig(config: Partial) { + this.log.info(`Updating bot config ${Object.keys(config).join(', ')}`); + this.config = { ...this.config, ...config }; + } + public async run() { const logCtx = { runId: Date.now() * 1000 + Math.floor(Math.random() * 1000) }; const { privateTransfersPerTx, publicTransfersPerTx, feePaymentMethod } = this.config; @@ -40,7 +45,7 @@ export class Bot { const sender = wallet.getAddress(); this.log.verbose( - `Sending tx with ${feePaymentMethod} fee with ${privateTransfersPerTx} private and ${publicTransfersPerTx} public transfers`, + `Preparing tx with ${feePaymentMethod} fee with ${privateTransfersPerTx} private and ${publicTransfersPerTx} public transfers`, logCtx, ); @@ -51,11 +56,7 @@ export class Bot { ), ]; - const paymentMethod = - feePaymentMethod === 'fee_juice' ? new FeeJuicePaymentMethod(sender) : new NoFeePaymentMethod(); - const gasSettings = GasSettings.default(); - const opts: SendMethodOptions = { estimateGas: true, fee: { paymentMethod, gasSettings } }; - + const opts = this.getSendMethodOpts(); const batch = new BatchCall(wallet, calls); this.log.verbose(`Creating batch execution request with ${calls.length} calls`, logCtx); await batch.create(opts); @@ -94,4 +95,23 @@ export class Bot { recipient: await getBalances(this.token, this.recipient), }; } + + private getSendMethodOpts(): SendMethodOptions { + const sender = this.wallet.getAddress(); + const { feePaymentMethod, l2GasLimit, daGasLimit } = this.config; + const paymentMethod = + feePaymentMethod === 'fee_juice' ? new FeeJuicePaymentMethod(sender) : new NoFeePaymentMethod(); + + let gasSettings, estimateGas; + if (l2GasLimit !== undefined && l2GasLimit > 0 && daGasLimit !== undefined && daGasLimit > 0) { + gasSettings = GasSettings.default({ gasLimits: Gas.from({ l2Gas: l2GasLimit, daGas: daGasLimit }) }); + estimateGas = false; + this.log.verbose(`Using gas limits: ${l2GasLimit} L2 gas, ${daGasLimit} DA gas`); + } else { + gasSettings = GasSettings.default(); + estimateGas = true; + this.log.verbose(`Estimating gas for transaction`); + } + return { estimateGas, fee: { paymentMethod, gasSettings } }; + } } diff --git a/yarn-project/bot/src/config.ts b/yarn-project/bot/src/config.ts index d2753d3b57f..7d896ac5023 100644 --- a/yarn-project/bot/src/config.ts +++ b/yarn-project/bot/src/config.ts @@ -5,6 +5,7 @@ import { getConfigFromMappings, getDefaultConfig, numberConfigHelper, + optionalNumberConfigHelper, } from '@aztec/foundation/config'; const botFollowChain = ['NONE', 'PENDING', 'PROVEN'] as const; @@ -39,6 +40,12 @@ export type BotConfig = { maxPendingTxs: number; /** Whether to flush after sending each 'setup' transaction */ flushSetupTransactions: boolean; + /** Whether to skip public simulation of txs before sending them. */ + skipPublicSimulation: boolean; + /** L2 gas limit for the tx (empty to have the bot trigger an estimate gas). */ + l2GasLimit: number | undefined; + /** DA gas limit for the tx (empty to have the bot trigger an estimate gas). */ + daGasLimit: number | undefined; }; export const botConfigMappings: ConfigMappingsType = { @@ -120,6 +127,21 @@ export const botConfigMappings: ConfigMappingsType = { description: 'Make a request for the sequencer to build a block after each setup transaction.', ...booleanConfigHelper(false), }, + skipPublicSimulation: { + env: 'BOT_SKIP_PUBLIC_SIMULATION', + description: 'Whether to skip public simulation of txs before sending them.', + ...booleanConfigHelper(false), + }, + l2GasLimit: { + env: 'BOT_L2_GAS_LIMIT', + description: 'L2 gas limit for the tx (empty to have the bot trigger an estimate gas).', + ...optionalNumberConfigHelper(), + }, + daGasLimit: { + env: 'BOT_DA_GAS_LIMIT', + description: 'DA gas limit for the tx (empty to have the bot trigger an estimate gas).', + ...optionalNumberConfigHelper(), + }, }; export function getBotConfigFromEnv(): BotConfig { diff --git a/yarn-project/end-to-end/src/e2e_bot.test.ts b/yarn-project/end-to-end/src/e2e_bot.test.ts index 1296122c222..1f1c26a24e2 100644 --- a/yarn-project/end-to-end/src/e2e_bot.test.ts +++ b/yarn-project/end-to-end/src/e2e_bot.test.ts @@ -24,10 +24,22 @@ describe('e2e_bot', () => { afterAll(() => teardown()); it('sends token transfers from the bot', async () => { + const { recipient: recipientBefore } = await bot.getBalances(); + + await bot.run(); + const { recipient: recipientAfter } = await bot.getBalances(); + expect(recipientAfter.privateBalance - recipientBefore.privateBalance).toEqual(1n); + expect(recipientAfter.publicBalance - recipientBefore.publicBalance).toEqual(1n); + }); + + it('sends token transfers with hardcoded gas and no simulation', async () => { + bot.updateConfig({ daGasLimit: 1e9, l2GasLimit: 1e9, skipPublicSimulation: true }); + const { recipient: recipientBefore } = await bot.getBalances(); + await bot.run(); - const balances = await bot.getBalances(); - expect(balances.recipient.privateBalance).toEqual(1n); - expect(balances.recipient.publicBalance).toEqual(1n); + const { recipient: recipientAfter } = await bot.getBalances(); + expect(recipientAfter.privateBalance - recipientBefore.privateBalance).toEqual(1n); + expect(recipientAfter.publicBalance - recipientBefore.publicBalance).toEqual(1n); }); it('reuses the same account and token contract', async () => { diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index f29bb79ad18..43072be644c 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -95,6 +95,9 @@ export type EnvVar = | 'BOT_TX_MINED_WAIT_SECONDS' | 'BOT_NO_WAIT_FOR_TRANSFERS' | 'BOT_MAX_PENDING_TXS' + | 'BOT_SKIP_PUBLIC_SIMULATION' + | 'BOT_L2_GAS_LIMIT' + | 'BOT_DA_GAS_LIMIT' | 'PXE_BLOCK_POLLING_INTERVAL_MS' | 'PXE_L2_STARTING_BLOCK' | 'PXE_DATA_DIRECTORY' diff --git a/yarn-project/foundation/src/config/index.ts b/yarn-project/foundation/src/config/index.ts index 2a31a008cc7..68b14921785 100644 --- a/yarn-project/foundation/src/config/index.ts +++ b/yarn-project/foundation/src/config/index.ts @@ -67,6 +67,21 @@ export function numberConfigHelper(defaultVal: number): Pick { + return { + parseEnv: (val: string | undefined) => { + if (val !== undefined && val.length > 0) { + const parsedValue = parseInt(val); + return Number.isSafeInteger(parsedValue) ? parsedValue : undefined; + } + return undefined; + }, + }; +} + /** * Generates parseEnv and default values for a boolean config value. * @param defaultVal - The default value to use if the environment variable is not set or is invalid