From 5a076df09afdb26082b54ac58271cdcfc882fa64 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 23 Jan 2026 00:40:26 +0400 Subject: [PATCH] feat: allow setting custom debug block provider (#21345) Co-authored-by: Karl --- crates/node/builder/src/launch/debug.rs | 79 +++++++++++++++++++++---- crates/node/builder/src/lib.rs | 2 +- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/crates/node/builder/src/launch/debug.rs b/crates/node/builder/src/launch/debug.rs index a623a825ad..896f56fb61 100644 --- a/crates/node/builder/src/launch/debug.rs +++ b/crates/node/builder/src/launch/debug.rs @@ -4,10 +4,13 @@ use alloy_consensus::transaction::Either; use alloy_provider::network::AnyNetwork; use jsonrpsee::core::{DeserializeOwned, Serialize}; use reth_chainspec::EthChainSpec; -use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider}; +use reth_consensus_debug_client::{ + BlockProvider, DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider, +}; use reth_engine_local::LocalMiner; use reth_node_api::{ - BlockTy, FullNodeComponents, HeaderTy, PayloadAttrTy, PayloadAttributesBuilder, PayloadTypes, + BlockTy, FullNodeComponents, FullNodeTypes, HeaderTy, PayloadAttrTy, PayloadAttributesBuilder, + PayloadTypes, }; use std::{ future::{Future, IntoFuture}, @@ -109,9 +112,16 @@ impl DebugNodeLauncher { } } +/// Type alias for the default debug block provider. We use etherscan provider to satisfy the +/// bounds. +pub type DefaultDebugBlockProvider = EtherscanBlockProvider< + <::Types as DebugNode>::RpcBlock, + BlockTy<::Types>, +>; + /// Future for the [`DebugNodeLauncher`]. #[expect(missing_debug_implementations, clippy::type_complexity)] -pub struct DebugNodeLauncherFuture +pub struct DebugNodeLauncherFuture> where N: FullNodeComponents>, { @@ -121,14 +131,17 @@ where Option, HeaderTy>>>, map_attributes: Option) -> PayloadAttrTy + Send + Sync>>, + debug_block_provider: Option, } -impl DebugNodeLauncherFuture +impl DebugNodeLauncherFuture where N: FullNodeComponents>, AddOns: RethRpcAddOns, L: LaunchNode>, + B: BlockProvider> + Clone, { + /// Sets a custom payload attributes builder for local mining in dev mode. pub fn with_payload_attributes_builder( self, builder: impl PayloadAttributesBuilder, HeaderTy>, @@ -138,9 +151,11 @@ where target: self.target, local_payload_attributes_builder: Some(Box::new(builder)), map_attributes: None, + debug_block_provider: self.debug_block_provider, } } + /// Sets a function to map payload attributes before building. pub fn map_debug_payload_attributes( self, f: impl Fn(PayloadAttrTy) -> PayloadAttrTy + Send + Sync + 'static, @@ -150,16 +165,58 @@ where target: self.target, local_payload_attributes_builder: None, map_attributes: Some(Box::new(f)), + debug_block_provider: self.debug_block_provider, + } + } + + /// Sets a custom block provider for the debug consensus client. + /// + /// When set, this provider will be used instead of creating an `EtherscanBlockProvider` + /// or `RpcBlockProvider` from CLI arguments. + pub fn with_debug_block_provider( + self, + provider: B2, + ) -> DebugNodeLauncherFuture + where + B2: BlockProvider> + Clone, + { + DebugNodeLauncherFuture { + inner: self.inner, + target: self.target, + local_payload_attributes_builder: self.local_payload_attributes_builder, + map_attributes: self.map_attributes, + debug_block_provider: Some(provider), } } async fn launch_node(self) -> eyre::Result> { - let Self { inner, target, local_payload_attributes_builder, map_attributes } = self; + let Self { + inner, + target, + local_payload_attributes_builder, + map_attributes, + debug_block_provider, + } = self; let handle = inner.launch_node(target).await?; let config = &handle.node.config; - if let Some(url) = config.debug.rpc_consensus_url.clone() { + + if let Some(provider) = debug_block_provider { + info!(target: "reth::cli", "Using custom debug block provider"); + + let rpc_consensus_client = DebugConsensusClient::new( + handle.node.add_ons_handle.beacon_engine_handle.clone(), + Arc::new(provider), + ); + + handle + .node + .task_executor + .spawn_critical("custom debug block provider consensus client", async move { + rpc_consensus_client.run().await + }); + } else if let Some(url) = config.debug.rpc_consensus_url.clone() { info!(target: "reth::cli", "Using RPC consensus client: {}", url); let block_provider = @@ -180,14 +237,11 @@ where handle.node.task_executor.spawn_critical("rpc-ws consensus client", async move { rpc_consensus_client.run().await }); - } - - if let Some(maybe_custom_etherscan_url) = config.debug.etherscan.clone() { + } else if let Some(maybe_custom_etherscan_url) = config.debug.etherscan.clone() { info!(target: "reth::cli", "Using etherscan as consensus client"); let chain = config.chain.chain(); let etherscan_url = maybe_custom_etherscan_url.map(Ok).unwrap_or_else(|| { - // If URL isn't provided, use default Etherscan URL for the chain if it is known chain .etherscan_urls() .map(|urls| urls.0.to_string()) @@ -252,12 +306,13 @@ where } } -impl IntoFuture for DebugNodeLauncherFuture +impl IntoFuture for DebugNodeLauncherFuture where Target: Send + 'static, N: FullNodeComponents>, AddOns: RethRpcAddOns + 'static, L: LaunchNode> + 'static, + B: BlockProvider> + Clone + 'static, { type Output = eyre::Result>; type IntoFuture = Pin>> + Send>>; @@ -273,6 +328,7 @@ where N: FullNodeComponents>, AddOns: RethRpcAddOns + 'static, L: LaunchNode> + 'static, + DefaultDebugBlockProvider: BlockProvider> + Clone, { type Node = NodeHandle; type Future = DebugNodeLauncherFuture; @@ -283,6 +339,7 @@ where target, local_payload_attributes_builder: None, map_attributes: None, + debug_block_provider: None, } } } diff --git a/crates/node/builder/src/lib.rs b/crates/node/builder/src/lib.rs index 1218465e95..7f1e71d5c1 100644 --- a/crates/node/builder/src/lib.rs +++ b/crates/node/builder/src/lib.rs @@ -31,7 +31,7 @@ pub use builder::{add_ons::AddOns, *}; mod launch; pub use launch::{ - debug::{DebugNode, DebugNodeLauncher}, + debug::{DebugNode, DebugNodeLauncher, DebugNodeLauncherFuture, DefaultDebugBlockProvider}, engine::EngineNodeLauncher, *, };