From 75aec913a977c255240737ebefc20393f5710a4b Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 16 Aug 2024 13:34:40 -0300 Subject: [PATCH] feat: Add max pending txs to bot 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. --- .../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 | 13 ++++++++++++ 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, 45 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 9d2dfd36cb99..3b951bc580c1 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -385,6 +385,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 0888b9dbf638..4d45dd4e0db0 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 d1e2f1121da7..9748e4f57e13 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 01f38ce3e7a5..bc1e1705d325 100644 --- a/yarn-project/bot/src/config.ts +++ b/yarn-project/bot/src/config.ts @@ -8,6 +8,8 @@ import { } from '@aztec/foundation/config'; 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. */ @@ -30,9 +32,15 @@ export type BotConfig = { txMinedWaitSeconds: number; /** Don't wait for transfer transactions. */ noWaitForTransfers: boolean; + /** 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.', @@ -91,6 +99,11 @@ export const botConfigMappings: ConfigMappingsType = { description: "Don't wait for transfer transactions.", ...booleanConfigHelper(), }, + 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 3a5206c7f99c..6159c7c605d4 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 73fd5f61f8ac..fc712a7339fb 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 cc45692f3e4e..845fb2394cd5 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'