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 gas_limit_ramp;
10mod generate_big_block;
11pub(crate) mod helpers;
12pub use generate_big_block::{
13 RawTransaction, RpcTransactionSource, TransactionCollector, TransactionSource,
14};
15mod new_payload_fcu;
16mod new_payload_only;
17mod output;
18mod replay_payloads;
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 builds empty blocks with a ramped gas limit.
39 GasLimitRamp(gas_limit_ramp::Command),
40
41 /// Benchmark which only calls subsequent `newPayload` calls.
42 NewPayloadOnly(new_payload_only::Command),
43
44 /// Command for generating and sending an `engine_newPayload` request constructed from an RPC
45 /// block.
46 ///
47 /// This command takes a JSON block input (either from a file or stdin) and generates
48 /// an execution payload that can be used with the `engine_newPayloadV*` API.
49 ///
50 /// One powerful use case is pairing this command with the `cast block` command, for example:
51 ///
52 /// `cast block latest --full --json | reth-bench send-payload --rpc-url localhost:5000
53 /// --jwt-secret $(cat ~/.local/share/reth/mainnet/jwt.hex)`
54 SendPayload(send_payload::Command),
55
56 /// Generate a large block by packing transactions from existing blocks.
57 ///
58 /// This command fetches transactions from real blocks and packs them into a single
59 /// block using the `testing_buildBlockV1` RPC endpoint.
60 ///
61 /// Example:
62 ///
63 /// `reth-bench generate-big-block --rpc-url http://localhost:8545 --engine-rpc-url
64 /// http://localhost:8551 --jwt-secret ~/.local/share/reth/mainnet/jwt.hex --target-gas
65 /// 30000000`
66 GenerateBigBlock(generate_big_block::Command),
67
68 /// Replay pre-generated payloads from a directory.
69 ///
70 /// This command reads payload files from a previous `generate-big-block` run and replays
71 /// them in sequence using `newPayload` followed by `forkchoiceUpdated`.
72 ///
73 /// Example:
74 ///
75 /// `reth-bench replay-payloads --payload-dir ./payloads --engine-rpc-url
76 /// http://localhost:8551 --jwt-secret ~/.local/share/reth/mainnet/jwt.hex`
77 ReplayPayloads(replay_payloads::Command),
78
79 /// Generate and send an invalid `engine_newPayload` request for testing.
80 ///
81 /// Takes a valid block and modifies fields to make it invalid, allowing you to test
82 /// Engine API rejection behavior. Block hash is recalculated after modifications
83 /// unless `--invalid-block-hash` or `--skip-hash-recalc` is used.
84 ///
85 /// Example:
86 ///
87 /// `cast block latest --full --json | reth-bench send-invalid-payload --rpc-url localhost:5000
88 /// --jwt-secret $(cat ~/.local/share/reth/mainnet/jwt.hex) --invalid-state-root`
89 SendInvalidPayload(Box<send_invalid_payload::Command>),
90}
91
92impl BenchmarkCommand {
93 /// Execute `benchmark` command
94 pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> {
95 // Initialize tracing
96 let _guard = self.init_tracing()?;
97
98 match self.command {
99 Subcommands::NewPayloadFcu(command) => command.execute(ctx).await,
100 Subcommands::GasLimitRamp(command) => command.execute(ctx).await,
101 Subcommands::NewPayloadOnly(command) => command.execute(ctx).await,
102 Subcommands::SendPayload(command) => command.execute(ctx).await,
103 Subcommands::GenerateBigBlock(command) => command.execute(ctx).await,
104 Subcommands::ReplayPayloads(command) => command.execute(ctx).await,
105 Subcommands::SendInvalidPayload(command) => (*command).execute(ctx).await,
106 }
107 }
108
109 /// Initializes tracing with the configured options.
110 ///
111 /// If file logging is enabled, this function returns a guard that must be kept alive to ensure
112 /// that all logs are flushed to disk.
113 pub fn init_tracing(&self) -> eyre::Result<Option<FileWorkerGuard>> {
114 let guard = self.logs.init_tracing()?;
115 Ok(guard)
116 }
117}