From 7f5517ecf19e720176d4e97e07f7be557b6705d9 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 19 Aug 2024 08:15:29 -0300 Subject: [PATCH] feat: Add max pending txs to bot (#8046) Adds a config to txs bot so it does not send more txs if there are more than N pending txs. Adds a requirement for an AZTEC_NODE_URL to be passed into the bot runner. Co-authored-by: PhilWindle <60546371+PhilWindle@users.noreply.github.com> --- .../aztec-node/src/aztec-node/server.ts | 4 ++++ yarn-project/aztec/src/cli/cmds/start_bot.ts | 6 +++--- yarn-project/aztec/src/cli/cmds/start_node.ts | 2 +- yarn-project/bot/src/config.ts | 14 +++++++++++++ yarn-project/bot/src/runner.ts | 21 +++++++++++++++---- .../src/interfaces/aztec-node.ts | 6 ++++++ yarn-project/foundation/src/config/env_var.ts | 1 + 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 4276621579e..c7a4f0144fe 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -379,6 +379,10 @@ export class AztecNodeService implements AztecNode { return Promise.resolve(this.p2pClient!.getTxs('pending')); } + public getPendingTxCount() { + return Promise.resolve(this.p2pClient!.getTxs('pending').length); + } + /** * Method to retrieve a single tx from the mempool or unfinalised chain. * @param txHash - The transaction hash to return. diff --git a/yarn-project/aztec/src/cli/cmds/start_bot.ts b/yarn-project/aztec/src/cli/cmds/start_bot.ts index 0888b9dbf63..4d45dd4e0db 100644 --- a/yarn-project/aztec/src/cli/cmds/start_bot.ts +++ b/yarn-project/aztec/src/cli/cmds/start_bot.ts @@ -1,5 +1,5 @@ import { type BotConfig, BotRunner, botConfigMappings, createBotRunnerRpcServer } from '@aztec/bot'; -import { type PXE } from '@aztec/circuit-types'; +import { type AztecNode, type PXE } from '@aztec/circuit-types'; import { type ServerList } from '@aztec/foundation/json-rpc/server'; import { type LogFn } from '@aztec/foundation/log'; @@ -35,11 +35,11 @@ export function addBot( options: any, services: ServerList, signalHandlers: (() => Promise)[], - deps: { pxe?: PXE } = {}, + deps: { pxe?: PXE; node?: AztecNode } = {}, ) { const config = extractRelevantOptions(options, botConfigMappings); - const botRunner = new BotRunner(config, { pxe: deps.pxe }); + const botRunner = new BotRunner(config, deps); const botServer = createBotRunnerRpcServer(botRunner); if (!config.noStart) { void botRunner.start(); // Do not block since bot setup takes time diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts index d1e2f1121da..9748e4f57e1 100644 --- a/yarn-project/aztec/src/cli/cmds/start_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -113,7 +113,7 @@ export const startNode = async ( // Add a txs bot if requested if (options.bot) { const { addBot } = await import('./start_bot.js'); - await addBot(options, services, signalHandlers, { pxe }); + await addBot(options, services, signalHandlers, { pxe, node }); } return services; diff --git a/yarn-project/bot/src/config.ts b/yarn-project/bot/src/config.ts index 4512902f7c1..08c9cc2939e 100644 --- a/yarn-project/bot/src/config.ts +++ b/yarn-project/bot/src/config.ts @@ -11,6 +11,8 @@ const botFollowChain = ['NONE', 'PENDING', 'PROVEN'] as const; type BotFollowChain = (typeof botFollowChain)[number]; export type BotConfig = { + /** The URL to the Aztec node to check for tx pool status. */ + nodeUrl: string | undefined; /** URL to the PXE for sending txs, or undefined if an in-proc PXE is used. */ pxeUrl: string | undefined; /** Signing private key for the sender account. */ @@ -31,10 +33,17 @@ export type BotConfig = { noStart: boolean; /** How long to wait for a tx to be mined before reporting an error. */ txMinedWaitSeconds: number; + /** Whether to wait for txs to be proven, to be mined, or no wait at all. */ followChain: BotFollowChain; + /** Do not send a tx if the node's tx pool already has this many pending txs. */ + maxPendingTxs: number; }; export const botConfigMappings: ConfigMappingsType = { + nodeUrl: { + env: 'AZTEC_NODE_URL', + description: 'The URL to the Aztec node to check for tx pool status.', + }, pxeUrl: { env: 'BOT_PXE_URL', description: 'URL to the PXE for sending txs, or undefined if an in-proc PXE is used.', @@ -99,6 +108,11 @@ export const botConfigMappings: ConfigMappingsType = { return val as BotFollowChain; }, }, + maxPendingTxs: { + env: 'BOT_MAX_PENDING_TXS', + description: "Do not send a tx if the node's tx pool already has this many pending txs.", + ...numberConfigHelper(128), + }, }; export function getBotConfigFromEnv(): BotConfig { diff --git a/yarn-project/bot/src/runner.ts b/yarn-project/bot/src/runner.ts index 3a5206c7f99..6159c7c605d 100644 --- a/yarn-project/bot/src/runner.ts +++ b/yarn-project/bot/src/runner.ts @@ -1,4 +1,4 @@ -import { type PXE, createDebugLogger } from '@aztec/aztec.js'; +import { type AztecNode, type PXE, createAztecNodeClient, createDebugLogger } from '@aztec/aztec.js'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { Bot } from './bot.js'; @@ -8,11 +8,16 @@ export class BotRunner { private log = createDebugLogger('aztec:bot'); private bot?: Promise; private pxe?: PXE; + private node: AztecNode; private runningPromise: RunningPromise; - public constructor(private config: BotConfig, dependencies: { pxe?: PXE } = {}) { + public constructor(private config: BotConfig, dependencies: { pxe?: PXE; node?: AztecNode }) { this.pxe = dependencies.pxe; - this.runningPromise = new RunningPromise(() => this.#safeRun(), config.txIntervalSeconds * 1000); + if (!dependencies.node && !config.nodeUrl) { + throw new Error(`Missing node URL in config or dependencies`); + } + this.node = dependencies.node ?? createAztecNodeClient(config.nodeUrl!); + this.runningPromise = new RunningPromise(() => this.#work(), config.txIntervalSeconds * 1000); } /** Initializes the bot if needed. Blocks until the bot setup is finished. */ @@ -112,7 +117,15 @@ export class BotRunner { } } - async #safeRun() { + async #work() { + if (this.config.maxPendingTxs > 0) { + const pendingTxs = await this.node.getPendingTxs(); + if (pendingTxs.length >= this.config.maxPendingTxs) { + this.log.verbose(`Not sending bot tx since node has ${pendingTxs.length} pending txs`); + return; + } + } + try { await this.run(); } catch (err) { diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index e90cc950978..d99d95c9a13 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -283,6 +283,12 @@ export interface AztecNode { */ getPendingTxs(): Promise; + /** + * Retrieves the number of pending txs + * @returns The number of pending txs. + */ + getPendingTxCount(): Promise; + /** * Method to retrieve a single pending tx. * @param txHash - The transaction hash to return. diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index 438571ed225..cf78a19e91b 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -89,6 +89,7 @@ export type EnvVar = | 'BOT_NO_START' | 'BOT_TX_MINED_WAIT_SECONDS' | 'BOT_NO_WAIT_FOR_TRANSFERS' + | 'BOT_MAX_PENDING_TXS' | 'PXE_BLOCK_POLLING_INTERVAL_MS' | 'PXE_L2_STARTING_BLOCK' | 'PXE_DATA_DIRECTORY'