Skip to main content

reth_bench/bench/
mod.rs

1//! `reth benchmark` command. Collection of various benchmarking routines.
2
3use clap::{Parser, Subcommand};
4use reth_cli_runner::CliContext;
5use reth_node_core::args::LogArgs;
6use reth_tracing::FileWorkerGuard;
7
8mod context;
9mod generate_big_block;
10pub(crate) mod helpers;
11pub use generate_big_block::{
12    compute_payload_block_hash, RawTransaction, RpcTransactionSource, TransactionCollector,
13    TransactionSource,
14};
15pub(crate) mod metrics_scraper;
16mod new_payload_fcu;
17mod new_payload_only;
18mod output;
19mod send_invalid_payload;
20mod send_payload;
21
22/// `reth bench` command
23#[derive(Debug, Parser)]
24pub struct BenchmarkCommand {
25    #[command(subcommand)]
26    command: Subcommands,
27
28    #[command(flatten)]
29    logs: LogArgs,
30}
31
32/// `reth benchmark` subcommands
33#[derive(Subcommand, Debug)]
34pub enum Subcommands {
35    /// Benchmark which calls `newPayload`, then `forkchoiceUpdated`.
36    NewPayloadFcu(new_payload_fcu::Command),
37
38    /// Benchmark which only calls subsequent `newPayload` calls.
39    NewPayloadOnly(new_payload_only::Command),
40
41    /// Command for generating and sending an `engine_newPayload` request constructed from an RPC
42    /// block.
43    ///
44    /// This command takes a JSON block input (either from a file or stdin) and generates
45    /// an execution payload that can be used with the `engine_newPayloadV*` API.
46    ///
47    /// One powerful use case is pairing this command with the `cast block` command, for example:
48    ///
49    /// `cast block latest --full --json | reth-bench send-payload --rpc-url localhost:5000
50    /// --jwt-secret $(cat ~/.local/share/reth/mainnet/jwt.hex)`
51    SendPayload(send_payload::Command),
52
53    /// Generate a large block by merging consecutive blocks from an RPC.
54    ///
55    /// Fetches N consecutive blocks, takes block 0 as the base payload, concatenates
56    /// transactions from blocks 1..N-1, and saves the result to disk as a JSON file
57    /// containing the merged execution data and environment switches at block boundaries.
58    ///
59    /// Example:
60    ///
61    /// `reth-bench generate-big-block --rpc-url http://localhost:8545 --from-block 20000000
62    /// --count 10 --output-dir ./payloads`
63    GenerateBigBlock(generate_big_block::Command),
64
65    /// Generate and send an invalid `engine_newPayload` request for testing.
66    ///
67    /// Takes a valid block and modifies fields to make it invalid, allowing you to test
68    /// Engine API rejection behavior. Block hash is recalculated after modifications
69    /// unless `--invalid-block-hash` or `--skip-hash-recalc` is used.
70    ///
71    /// Example:
72    ///
73    /// `cast block latest --full --json | reth-bench send-invalid-payload --rpc-url localhost:5000
74    /// --jwt-secret $(cat ~/.local/share/reth/mainnet/jwt.hex) --invalid-state-root`
75    SendInvalidPayload(Box<send_invalid_payload::Command>),
76}
77
78impl BenchmarkCommand {
79    /// Execute `benchmark` command
80    pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> {
81        // Initialize tracing
82        let _guard = self.init_tracing()?;
83
84        match self.command {
85            Subcommands::NewPayloadFcu(command) => command.execute(ctx).await,
86            Subcommands::NewPayloadOnly(command) => command.execute(ctx).await,
87            Subcommands::SendPayload(command) => command.execute(ctx).await,
88            Subcommands::GenerateBigBlock(command) => command.execute(ctx).await,
89            Subcommands::SendInvalidPayload(command) => (*command).execute(ctx).await,
90        }
91    }
92
93    /// Initializes tracing with the configured options.
94    ///
95    /// If file logging is enabled, this function returns a guard that must be kept alive to ensure
96    /// that all logs are flushed to disk.
97    ///
98    /// Always enables log target display (`RUST_LOG_TARGET=1`) so that the `reth-bench` target
99    /// is visible in output, making it easy to distinguish reth-bench logs from reth logs when
100    /// both are streamed to the same console or file.
101    pub fn init_tracing(&self) -> eyre::Result<Option<FileWorkerGuard>> {
102        // Always show the log target so "reth-bench" is visible in the output.
103        if std::env::var_os("RUST_LOG_TARGET").is_none() {
104            // SAFETY: This is called early during single-threaded initialization, before any
105            // threads are spawned and before the tracing subscriber is set up.
106            unsafe { std::env::set_var("RUST_LOG_TARGET", "1") };
107        }
108
109        let guard = self.logs.init_tracing()?;
110        Ok(guard)
111    }
112}