Skip to content

Commit

Permalink
feat: Add bot config to toggle simulation (#8297)
Browse files Browse the repository at this point in the history
Allow turning off simulation and gas estimation on the bot via config.
  • Loading branch information
spalladino authored Sep 2, 2024
1 parent 6a2614a commit 1c7c447
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 11 deletions.
36 changes: 28 additions & 8 deletions yarn-project/bot/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -25,22 +25,27 @@ 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<Bot> {
const { wallet, token, recipient } = await new BotFactory(config, dependencies).setup();
return new Bot(wallet, token, recipient, config);
}

public updateConfig(config: Partial<BotConfig>) {
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;
const { token, recipient, wallet } = this;
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,
);

Expand All @@ -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);
Expand Down Expand Up @@ -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 } };
}
}
22 changes: 22 additions & 0 deletions yarn-project/bot/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getConfigFromMappings,
getDefaultConfig,
numberConfigHelper,
optionalNumberConfigHelper,
} from '@aztec/foundation/config';

const botFollowChain = ['NONE', 'PENDING', 'PROVEN'] as const;
Expand Down Expand Up @@ -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<BotConfig> = {
Expand Down Expand Up @@ -120,6 +127,21 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
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 {
Expand Down
18 changes: 15 additions & 3 deletions yarn-project/end-to-end/src/e2e_bot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/foundation/src/config/env_var.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
15 changes: 15 additions & 0 deletions yarn-project/foundation/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ export function numberConfigHelper(defaultVal: number): Pick<ConfigMapping, 'par
};
}

/**
* Generates parseEnv for an optional numerical config value.
*/
export function optionalNumberConfigHelper(): Pick<ConfigMapping, 'parseEnv'> {
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
Expand Down

0 comments on commit 1c7c447

Please sign in to comment.