From 59fb25d892e697c4c90dc8c4ae9ae4c159287139 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 14 Jan 2026 16:24:19 +0100 Subject: [PATCH] feat(bench-compare): add --skip-wait-syncing flag (#21035) --- bin/reth-bench-compare/src/cli.rs | 23 ++++++++-- bin/reth-bench-compare/src/node.rs | 70 ++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/bin/reth-bench-compare/src/cli.rs b/bin/reth-bench-compare/src/cli.rs index 05680fb70e..db8cbfcf57 100644 --- a/bin/reth-bench-compare/src/cli.rs +++ b/bin/reth-bench-compare/src/cli.rs @@ -147,6 +147,11 @@ pub(crate) struct Args { #[arg(long)] pub no_clear_cache: bool, + /// Skip waiting for the node to sync before starting benchmarks. + /// When enabled, assumes the node is already synced and skips the initial tip check. + #[arg(long)] + pub skip_wait_syncing: bool, + #[command(flatten)] pub logs: LogArgs, @@ -578,7 +583,11 @@ async fn run_warmup_phase( node_manager.start_node(&binary_path, warmup_ref, "warmup", &additional_args).await?; // Wait for node to be ready and get its current tip - let current_tip = node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await?; + let current_tip = if args.skip_wait_syncing { + node_manager.wait_for_rpc_and_get_tip(&mut node_process).await? + } else { + node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await? + }; info!("Warmup node is ready at tip: {}", current_tip); // Clear filesystem caches before warmup run only (unless disabled) @@ -632,7 +641,11 @@ async fn run_benchmark_workflow( let (mut node_process, _) = node_manager .start_node(&binary_path, &args.baseline_ref, "baseline", &additional_args) .await?; - let starting_tip = node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await?; + let starting_tip = if args.skip_wait_syncing { + node_manager.wait_for_rpc_and_get_tip(&mut node_process).await? + } else { + node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await? + }; info!("Node starting tip: {}", starting_tip); node_manager.stop_node(&mut node_process).await?; @@ -699,7 +712,11 @@ async fn run_benchmark_workflow( node_manager.start_node(&binary_path, git_ref, ref_type, &additional_args).await?; // Wait for node to be ready and get its current tip (wherever it is) - let current_tip = node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await?; + let current_tip = if args.skip_wait_syncing { + node_manager.wait_for_rpc_and_get_tip(&mut node_process).await? + } else { + node_manager.wait_for_node_ready_and_get_tip(&mut node_process).await? + }; info!("Node is ready at tip: {}", current_tip); // Calculate benchmark range diff --git a/bin/reth-bench-compare/src/node.rs b/bin/reth-bench-compare/src/node.rs index 6bbd1ad536..66f86df977 100644 --- a/bin/reth-bench-compare/src/node.rs +++ b/bin/reth-bench-compare/src/node.rs @@ -458,6 +458,76 @@ impl NodeManager { .wrap_err("Timed out waiting for node to be ready and synced")? } + /// Wait for the node RPC to be ready and return its current tip, without waiting for sync. + /// + /// This is faster than `wait_for_node_ready_and_get_tip` but may return a tip while + /// the node is still syncing. + pub(crate) async fn wait_for_rpc_and_get_tip( + &self, + child: &mut tokio::process::Child, + ) -> Result { + info!("Waiting for node RPC to be ready (skipping sync wait)..."); + + let max_wait = Duration::from_secs(60); + let check_interval = Duration::from_secs(2); + let rpc_url = "http://localhost:8545"; + + let url = rpc_url.parse().map_err(|e| eyre!("Invalid RPC URL '{}': {}", rpc_url, e))?; + let provider = ProviderBuilder::new().connect_http(url); + + let start_time = tokio::time::Instant::now(); + let mut iteration = 0; + + timeout(max_wait, async { + loop { + iteration += 1; + debug!( + "RPC readiness check iteration {} (elapsed: {:?})", + iteration, + start_time.elapsed() + ); + + if let Some(status) = child.try_wait()? { + return Err(eyre!("Node process exited unexpectedly with {status}")); + } + + match provider.get_block_number().await { + Ok(tip) => { + debug!("HTTP RPC ready at block: {}, checking WebSocket...", tip); + + let ws_url = format!("ws://localhost:{}", DEFAULT_WS_RPC_PORT); + let ws_connect = WsConnect::new(&ws_url); + + match RpcClient::connect_pubsub(ws_connect).await { + Ok(_) => { + info!( + "Node RPC is ready at block: {} (took {:?}, {} iterations)", + tip, + start_time.elapsed(), + iteration + ); + return Ok(tip); + } + Err(e) => { + debug!( + "HTTP RPC ready but WebSocket not ready yet (iteration {}): {:?}", + iteration, e + ); + } + } + } + Err(e) => { + debug!("RPC not ready yet (iteration {}): {:?}", iteration, e); + } + } + + sleep(check_interval).await; + } + }) + .await + .wrap_err("Timed out waiting for node RPC to be ready")? + } + /// Stop the reth node gracefully pub(crate) async fn stop_node(&self, child: &mut tokio::process::Child) -> Result<()> { let pid = child.id().ok_or_eyre("Child process ID should be available")?;