reth_node_builder/builder/
mod.rs

1//! Customizable node builder.
2
3#![allow(clippy::type_complexity, missing_debug_implementations)]
4
5use crate::{
6    common::WithConfigs,
7    components::NodeComponentsBuilder,
8    node::FullNode,
9    rpc::{RethRpcAddOns, RethRpcServerHandles, RpcContext},
10    BlockReaderFor, DebugNode, DebugNodeLauncher, EngineNodeLauncher, LaunchNode, Node,
11};
12use alloy_eips::eip4844::env_settings::EnvKzgSettings;
13use futures::Future;
14use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
15use reth_db_api::{database::Database, database_metrics::DatabaseMetrics};
16use reth_exex::ExExContext;
17use reth_network::{
18    transactions::{TransactionPropagationPolicy, TransactionsManagerConfig},
19    NetworkBuilder, NetworkConfig, NetworkConfigBuilder, NetworkHandle, NetworkManager,
20    NetworkPrimitives,
21};
22use reth_node_api::{
23    FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes, NodeTypesWithDBAdapter,
24};
25use reth_node_core::{
26    cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig},
27    dirs::{ChainPath, DataDirPath},
28    node_config::NodeConfig,
29    primitives::Head,
30};
31use reth_provider::{
32    providers::{BlockchainProvider, NodeTypesForProvider},
33    ChainSpecProvider, FullProvider,
34};
35use reth_tasks::TaskExecutor;
36use reth_transaction_pool::{PoolConfig, PoolTransaction, TransactionPool};
37use secp256k1::SecretKey;
38use std::sync::Arc;
39use tracing::{info, trace, warn};
40
41pub mod add_ons;
42
43mod states;
44pub use states::*;
45
46/// The adapter type for a reth node with the builtin provider type
47// Note: we need to hardcode this because custom components might depend on it in associated types.
48pub type RethFullAdapter<DB, Types> =
49    FullNodeTypesAdapter<Types, DB, BlockchainProvider<NodeTypesWithDBAdapter<Types, DB>>>;
50
51#[expect(clippy::doc_markdown)]
52#[cfg_attr(doc, aquamarine::aquamarine)]
53/// Declaratively construct a node.
54///
55/// [`NodeBuilder`] provides a [builder-like interface][builder] for composing
56/// components of a node.
57///
58/// ## Order
59///
60/// Configuring a node starts out with a [`NodeConfig`] (this can be obtained from cli arguments for
61/// example) and then proceeds to configure the core static types of the node:
62/// [`NodeTypes`], these include the node's primitive types and the node's engine
63/// types.
64///
65/// Next all stateful components of the node are configured, these include all the
66/// components of the node that are downstream of those types, these include:
67///
68///  - The EVM and Executor configuration: [`ExecutorBuilder`](crate::components::ExecutorBuilder)
69///  - The transaction pool: [`PoolBuilder`](crate::components::PoolBuilder)
70///  - The network: [`NetworkBuilder`](crate::components::NetworkBuilder)
71///  - The payload builder: [`PayloadBuilder`](crate::components::PayloadServiceBuilder)
72///
73/// Once all the components are configured, the node is ready to be launched.
74///
75/// On launch the builder returns a fully type aware [`NodeHandle`] that has access to all the
76/// configured components and can interact with the node.
77///
78/// There are convenience functions for networks that come with a preset of types and components via
79/// the [`Node`] trait, see `reth_node_ethereum::EthereumNode` or `reth_optimism_node::OpNode`.
80///
81/// The [`NodeBuilder::node`] function configures the node's types and components in one step.
82///
83/// ## Components
84///
85/// All components are configured with a [`NodeComponentsBuilder`] that is responsible for actually
86/// creating the node components during the launch process. The
87/// [`ComponentsBuilder`](crate::components::ComponentsBuilder) is a general purpose implementation
88/// of the [`NodeComponentsBuilder`] trait that can be used to configure the executor, network,
89/// transaction pool and payload builder of the node. It enforces the correct order of
90/// configuration, for example the network and the payload builder depend on the transaction pool
91/// type that is configured first.
92///
93/// All builder traits are generic over the node types and are invoked with the [`BuilderContext`]
94/// that gives access to internals of the that are needed to configure the components. This include
95/// the original config, chain spec, the database provider and the task executor,
96///
97/// ## Hooks
98///
99/// Once all the components are configured, the builder can be used to set hooks that are run at
100/// specific points in the node's lifecycle. This way custom services can be spawned before the node
101/// is launched [`NodeBuilderWithComponents::on_component_initialized`], or once the rpc server(s)
102/// are launched [`NodeBuilderWithComponents::on_rpc_started`]. The
103/// [`NodeBuilderWithComponents::extend_rpc_modules`] can be used to inject custom rpc modules into
104/// the rpc server before it is launched. See also [`RpcContext`] All hooks accept a closure that is
105/// then invoked at the appropriate time in the node's launch process.
106///
107/// ## Flow
108///
109/// The [`NodeBuilder`] is intended to sit behind a CLI that provides the necessary [`NodeConfig`]
110/// input: [`NodeBuilder::new`]
111///
112/// From there the builder is configured with the node's types, components, and hooks, then launched
113/// with the [`WithLaunchContext::launch`] method. On launch all the builtin internals, such as the
114/// `Database` and its providers [`BlockchainProvider`] are initialized before the configured
115/// [`NodeComponentsBuilder`] is invoked with the [`BuilderContext`] to create the transaction pool,
116/// network, and payload builder components. When the RPC is configured, the corresponding hooks are
117/// invoked to allow for custom rpc modules to be injected into the rpc server:
118/// [`NodeBuilderWithComponents::extend_rpc_modules`]
119///
120/// Finally all components are created and all services are launched and a [`NodeHandle`] is
121/// returned that can be used to interact with the node: [`FullNode`]
122///
123/// The following diagram shows the flow of the node builder from CLI to a launched node.
124///
125/// include_mmd!("docs/mermaid/builder.mmd")
126///
127/// ## Internals
128///
129/// The node builder is fully type safe, it uses the [`NodeTypes`] trait to enforce that
130/// all components are configured with the correct types. However the database types and with that
131/// the provider trait implementations are currently created by the builder itself during the launch
132/// process, hence the database type is not part of the [`NodeTypes`] trait and the node's
133/// components, that depend on the database, are configured separately. In order to have a nice
134/// trait that encapsulates the entire node the
135/// [`FullNodeComponents`](reth_node_api::FullNodeComponents) trait was introduced. This
136/// trait has convenient associated types for all the components of the node. After
137/// [`WithLaunchContext::launch`] the [`NodeHandle`] contains an instance of [`FullNode`] that
138/// implements the [`FullNodeComponents`](reth_node_api::FullNodeComponents) trait and has access to
139/// all the components of the node. Internally the node builder uses several generic adapter types
140/// that are then map to traits with associated types for ease of use.
141///
142/// ### Limitations
143///
144/// Currently the launch process is limited to ethereum nodes and requires all the components
145/// specified above. It also expects beacon consensus with the ethereum engine API that is
146/// configured by the builder itself during launch. This might change in the future.
147///
148/// [builder]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
149pub struct NodeBuilder<DB, ChainSpec> {
150    /// All settings for how the node should be configured.
151    config: NodeConfig<ChainSpec>,
152    /// The configured database for the node.
153    database: DB,
154}
155
156impl<ChainSpec> NodeBuilder<(), ChainSpec> {
157    /// Create a new [`NodeBuilder`].
158    pub const fn new(config: NodeConfig<ChainSpec>) -> Self {
159        Self { config, database: () }
160    }
161}
162
163impl<DB, ChainSpec> NodeBuilder<DB, ChainSpec> {
164    /// Returns a reference to the node builder's config.
165    pub const fn config(&self) -> &NodeConfig<ChainSpec> {
166        &self.config
167    }
168
169    /// Returns a mutable reference to the node builder's config.
170    pub const fn config_mut(&mut self) -> &mut NodeConfig<ChainSpec> {
171        &mut self.config
172    }
173
174    /// Returns a reference to the node's database
175    pub const fn db(&self) -> &DB {
176        &self.database
177    }
178
179    /// Returns a mutable reference to the node's database
180    pub const fn db_mut(&mut self) -> &mut DB {
181        &mut self.database
182    }
183
184    /// Applies a fallible function to the builder.
185    pub fn try_apply<F, R>(self, f: F) -> Result<Self, R>
186    where
187        F: FnOnce(Self) -> Result<Self, R>,
188    {
189        f(self)
190    }
191
192    /// Applies a fallible function to the builder, if the condition is `true`.
193    pub fn try_apply_if<F, R>(self, cond: bool, f: F) -> Result<Self, R>
194    where
195        F: FnOnce(Self) -> Result<Self, R>,
196    {
197        if cond {
198            f(self)
199        } else {
200            Ok(self)
201        }
202    }
203
204    /// Apply a function to the builder
205    pub fn apply<F>(self, f: F) -> Self
206    where
207        F: FnOnce(Self) -> Self,
208    {
209        f(self)
210    }
211
212    /// Apply a function to the builder, if the condition is `true`.
213    pub fn apply_if<F>(self, cond: bool, f: F) -> Self
214    where
215        F: FnOnce(Self) -> Self,
216    {
217        if cond {
218            f(self)
219        } else {
220            self
221        }
222    }
223}
224
225impl<DB, ChainSpec: EthChainSpec> NodeBuilder<DB, ChainSpec> {
226    /// Configures the underlying database that the node will use.
227    pub fn with_database<D>(self, database: D) -> NodeBuilder<D, ChainSpec> {
228        NodeBuilder { config: self.config, database }
229    }
230
231    /// Preconfigure the builder with the context to launch the node.
232    ///
233    /// This provides the task executor and the data directory for the node.
234    pub const fn with_launch_context(self, task_executor: TaskExecutor) -> WithLaunchContext<Self> {
235        WithLaunchContext { builder: self, task_executor }
236    }
237
238    /// Creates an _ephemeral_ preconfigured node for testing purposes.
239    #[cfg(feature = "test-utils")]
240    pub fn testing_node(
241        self,
242        task_executor: TaskExecutor,
243    ) -> WithLaunchContext<
244        NodeBuilder<Arc<reth_db::test_utils::TempDatabase<reth_db::DatabaseEnv>>, ChainSpec>,
245    > {
246        let path = reth_db::test_utils::tempdir_path();
247        self.testing_node_with_datadir(task_executor, path)
248    }
249
250    /// Creates a preconfigured node for testing purposes with a specific datadir.
251    #[cfg(feature = "test-utils")]
252    pub fn testing_node_with_datadir(
253        mut self,
254        task_executor: TaskExecutor,
255        datadir: impl Into<std::path::PathBuf>,
256    ) -> WithLaunchContext<
257        NodeBuilder<Arc<reth_db::test_utils::TempDatabase<reth_db::DatabaseEnv>>, ChainSpec>,
258    > {
259        let path = reth_node_core::dirs::MaybePlatformPath::<DataDirPath>::from(datadir.into());
260        self.config = self.config.with_datadir_args(reth_node_core::args::DatadirArgs {
261            datadir: path.clone(),
262            ..Default::default()
263        });
264
265        let data_dir =
266            path.unwrap_or_chain_default(self.config.chain.chain(), self.config.datadir.clone());
267
268        let db = reth_db::test_utils::create_test_rw_db_with_path(data_dir.db());
269
270        WithLaunchContext { builder: self.with_database(db), task_executor }
271    }
272}
273
274impl<DB, ChainSpec> NodeBuilder<DB, ChainSpec>
275where
276    DB: Database + DatabaseMetrics + Clone + Unpin + 'static,
277    ChainSpec: EthChainSpec + EthereumHardforks,
278{
279    /// Configures the types of the node.
280    pub fn with_types<T>(self) -> NodeBuilderWithTypes<RethFullAdapter<DB, T>>
281    where
282        T: NodeTypesForProvider<ChainSpec = ChainSpec>,
283    {
284        self.with_types_and_provider()
285    }
286
287    /// Configures the types of the node and the provider type that will be used by the node.
288    pub fn with_types_and_provider<T, P>(
289        self,
290    ) -> NodeBuilderWithTypes<FullNodeTypesAdapter<T, DB, P>>
291    where
292        T: NodeTypesForProvider<ChainSpec = ChainSpec>,
293        P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
294    {
295        NodeBuilderWithTypes::new(self.config, self.database)
296    }
297
298    /// Preconfigures the node with a specific node implementation.
299    ///
300    /// This is a convenience method that sets the node's types and components in one call.
301    pub fn node<N>(
302        self,
303        node: N,
304    ) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>
305    where
306        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
307    {
308        self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
309    }
310}
311
312/// A [`NodeBuilder`] with its launch context already configured.
313///
314/// This exposes the same methods as [`NodeBuilder`] but with the launch context already configured,
315/// See [`WithLaunchContext::launch`]
316pub struct WithLaunchContext<Builder> {
317    builder: Builder,
318    task_executor: TaskExecutor,
319}
320
321impl<Builder> WithLaunchContext<Builder> {
322    /// Returns a reference to the task executor.
323    pub const fn task_executor(&self) -> &TaskExecutor {
324        &self.task_executor
325    }
326}
327
328impl<DB, ChainSpec> WithLaunchContext<NodeBuilder<DB, ChainSpec>> {
329    /// Returns a reference to the node builder's config.
330    pub const fn config(&self) -> &NodeConfig<ChainSpec> {
331        self.builder.config()
332    }
333
334    /// Returns a mutable reference to the node builder's config.
335    pub const fn config_mut(&mut self) -> &mut NodeConfig<ChainSpec> {
336        self.builder.config_mut()
337    }
338}
339
340impl<DB, ChainSpec> WithLaunchContext<NodeBuilder<DB, ChainSpec>>
341where
342    DB: Database + DatabaseMetrics + Clone + Unpin + 'static,
343    ChainSpec: EthChainSpec + EthereumHardforks,
344{
345    /// Configures the types of the node.
346    pub fn with_types<T>(self) -> WithLaunchContext<NodeBuilderWithTypes<RethFullAdapter<DB, T>>>
347    where
348        T: NodeTypesForProvider<ChainSpec = ChainSpec>,
349    {
350        WithLaunchContext { builder: self.builder.with_types(), task_executor: self.task_executor }
351    }
352
353    /// Configures the types of the node and the provider type that will be used by the node.
354    pub fn with_types_and_provider<T, P>(
355        self,
356    ) -> WithLaunchContext<NodeBuilderWithTypes<FullNodeTypesAdapter<T, DB, P>>>
357    where
358        T: NodeTypesForProvider<ChainSpec = ChainSpec>,
359        P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
360    {
361        WithLaunchContext {
362            builder: self.builder.with_types_and_provider(),
363            task_executor: self.task_executor,
364        }
365    }
366
367    /// Preconfigures the node with a specific node implementation.
368    ///
369    /// This is a convenience method that sets the node's types and components in one call.
370    pub fn node<N>(
371        self,
372        node: N,
373    ) -> WithLaunchContext<
374        NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
375    >
376    where
377        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
378    {
379        self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
380    }
381
382    /// Launches a preconfigured [Node]
383    ///
384    /// This bootstraps the node internals, creates all the components with the given [Node]
385    ///
386    /// Returns a [`NodeHandle`](crate::NodeHandle) that can be used to interact with the node.
387    pub async fn launch_node<N>(
388        self,
389        node: N,
390    ) -> eyre::Result<
391        <EngineNodeLauncher as LaunchNode<
392            NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
393        >>::Node,
394    >
395    where
396        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
397        N::AddOns: RethRpcAddOns<
398            NodeAdapter<
399                RethFullAdapter<DB, N>,
400                <N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
401            >,
402        >,
403        EngineNodeLauncher: LaunchNode<
404            NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
405        >,
406    {
407        self.node(node).launch().await
408    }
409}
410
411impl<T: FullNodeTypes> WithLaunchContext<NodeBuilderWithTypes<T>> {
412    /// Advances the state of the node builder to the next state where all components are configured
413    pub fn with_components<CB>(
414        self,
415        components_builder: CB,
416    ) -> WithLaunchContext<NodeBuilderWithComponents<T, CB, ()>>
417    where
418        CB: NodeComponentsBuilder<T>,
419    {
420        WithLaunchContext {
421            builder: self.builder.with_components(components_builder),
422            task_executor: self.task_executor,
423        }
424    }
425}
426
427impl<T, CB> WithLaunchContext<NodeBuilderWithComponents<T, CB, ()>>
428where
429    T: FullNodeTypes,
430    CB: NodeComponentsBuilder<T>,
431{
432    /// Advances the state of the node builder to the next state where all customizable
433    /// [`NodeAddOns`] types are configured.
434    pub fn with_add_ons<AO>(
435        self,
436        add_ons: AO,
437    ) -> WithLaunchContext<NodeBuilderWithComponents<T, CB, AO>>
438    where
439        AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
440    {
441        WithLaunchContext {
442            builder: self.builder.with_add_ons(add_ons),
443            task_executor: self.task_executor,
444        }
445    }
446}
447
448impl<T, CB, AO> WithLaunchContext<NodeBuilderWithComponents<T, CB, AO>>
449where
450    T: FullNodeTypes,
451    CB: NodeComponentsBuilder<T>,
452    AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
453{
454    /// Returns a reference to the node builder's config.
455    pub const fn config(&self) -> &NodeConfig<<T::Types as NodeTypes>::ChainSpec> {
456        &self.builder.config
457    }
458
459    /// Returns a mutable reference to the node builder's config.
460    pub const fn config_mut(&mut self) -> &mut NodeConfig<<T::Types as NodeTypes>::ChainSpec> {
461        &mut self.builder.config
462    }
463
464    /// Returns a reference to node's database.
465    pub const fn db(&self) -> &T::DB {
466        &self.builder.adapter.database
467    }
468
469    /// Returns a mutable reference to node's database.
470    pub const fn db_mut(&mut self) -> &mut T::DB {
471        &mut self.builder.adapter.database
472    }
473
474    /// Applies a fallible function to the builder.
475    pub fn try_apply<F, R>(self, f: F) -> Result<Self, R>
476    where
477        F: FnOnce(Self) -> Result<Self, R>,
478    {
479        f(self)
480    }
481
482    /// Applies a fallible function to the builder, if the condition is `true`.
483    pub fn try_apply_if<F, R>(self, cond: bool, f: F) -> Result<Self, R>
484    where
485        F: FnOnce(Self) -> Result<Self, R>,
486    {
487        if cond {
488            f(self)
489        } else {
490            Ok(self)
491        }
492    }
493
494    /// Apply a function to the builder
495    pub fn apply<F>(self, f: F) -> Self
496    where
497        F: FnOnce(Self) -> Self,
498    {
499        f(self)
500    }
501
502    /// Apply a function to the builder, if the condition is `true`.
503    pub fn apply_if<F>(self, cond: bool, f: F) -> Self
504    where
505        F: FnOnce(Self) -> Self,
506    {
507        if cond {
508            f(self)
509        } else {
510            self
511        }
512    }
513
514    /// Sets the hook that is run once the node's components are initialized.
515    pub fn on_component_initialized<F>(self, hook: F) -> Self
516    where
517        F: FnOnce(NodeAdapter<T, CB::Components>) -> eyre::Result<()> + Send + 'static,
518    {
519        Self {
520            builder: self.builder.on_component_initialized(hook),
521            task_executor: self.task_executor,
522        }
523    }
524
525    /// Sets the hook that is run once the node has started.
526    pub fn on_node_started<F>(self, hook: F) -> Self
527    where
528        F: FnOnce(FullNode<NodeAdapter<T, CB::Components>, AO>) -> eyre::Result<()>
529            + Send
530            + 'static,
531    {
532        Self { builder: self.builder.on_node_started(hook), task_executor: self.task_executor }
533    }
534
535    /// Modifies the addons with the given closure.
536    pub fn map_add_ons<F>(self, f: F) -> Self
537    where
538        F: FnOnce(AO) -> AO,
539    {
540        Self { builder: self.builder.map_add_ons(f), task_executor: self.task_executor }
541    }
542
543    /// Sets the hook that is run once the rpc server is started.
544    pub fn on_rpc_started<F>(self, hook: F) -> Self
545    where
546        F: FnOnce(
547                RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
548                RethRpcServerHandles,
549            ) -> eyre::Result<()>
550            + Send
551            + 'static,
552    {
553        Self { builder: self.builder.on_rpc_started(hook), task_executor: self.task_executor }
554    }
555
556    /// Sets the hook that is run to configure the rpc modules.
557    ///
558    /// This hook can obtain the node's components (txpool, provider, etc.) and can modify the
559    /// modules that the RPC server installs.
560    ///
561    /// # Examples
562    ///
563    /// ```rust,ignore
564    /// use jsonrpsee::{core::RpcResult, proc_macros::rpc};
565    ///
566    /// #[derive(Clone)]
567    /// struct CustomApi<Pool> { pool: Pool }
568    ///
569    /// #[rpc(server, namespace = "custom")]
570    /// impl CustomApi {
571    ///     #[method(name = "hello")]
572    ///     async fn hello(&self) -> RpcResult<String> {
573    ///         Ok("World".to_string())
574    ///     }
575    /// }
576    ///
577    /// let node = NodeBuilder::new(config)
578    ///     .node(EthereumNode::default())
579    ///     .extend_rpc_modules(|ctx| {
580    ///         // Access node components, so they can used by the CustomApi
581    ///         let pool = ctx.pool().clone();
582    ///         
583    ///         // Add custom RPC namespace
584    ///         ctx.modules.merge_configured(CustomApi { pool }.into_rpc())?;
585    ///         
586    ///         Ok(())
587    ///     })
588    ///     .build()?;
589    /// ```
590    pub fn extend_rpc_modules<F>(self, hook: F) -> Self
591    where
592        F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
593            + Send
594            + 'static,
595    {
596        Self { builder: self.builder.extend_rpc_modules(hook), task_executor: self.task_executor }
597    }
598
599    /// Installs an `ExEx` (Execution Extension) in the node.
600    ///
601    /// # Note
602    ///
603    /// The `ExEx` ID must be unique.
604    pub fn install_exex<F, R, E>(self, exex_id: impl Into<String>, exex: F) -> Self
605    where
606        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
607        R: Future<Output = eyre::Result<E>> + Send,
608        E: Future<Output = eyre::Result<()>> + Send,
609    {
610        Self {
611            builder: self.builder.install_exex(exex_id, exex),
612            task_executor: self.task_executor,
613        }
614    }
615
616    /// Installs an `ExEx` (Execution Extension) in the node if the condition is true.
617    ///
618    /// # Note
619    ///
620    /// The `ExEx` ID must be unique.
621    pub fn install_exex_if<F, R, E>(self, cond: bool, exex_id: impl Into<String>, exex: F) -> Self
622    where
623        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
624        R: Future<Output = eyre::Result<E>> + Send,
625        E: Future<Output = eyre::Result<()>> + Send,
626    {
627        if cond {
628            self.install_exex(exex_id, exex)
629        } else {
630            self
631        }
632    }
633
634    /// Launches the node with the given launcher.
635    pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
636    where
637        L: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
638    {
639        launcher.launch_node(self.builder).await
640    }
641
642    /// Launches the node with the given closure.
643    pub fn launch_with_fn<L, R>(self, launcher: L) -> R
644    where
645        L: FnOnce(Self) -> R,
646    {
647        launcher(self)
648    }
649
650    /// Check that the builder can be launched
651    ///
652    /// This is useful when writing tests to ensure that the builder is configured correctly.
653    pub const fn check_launch(self) -> Self {
654        self
655    }
656
657    /// Launches the node with the [`EngineNodeLauncher`] that sets up engine API consensus and rpc
658    pub async fn launch(
659        self,
660    ) -> eyre::Result<<EngineNodeLauncher as LaunchNode<NodeBuilderWithComponents<T, CB, AO>>>::Node>
661    where
662        EngineNodeLauncher: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
663    {
664        let launcher = self.engine_api_launcher();
665        self.builder.launch_with(launcher).await
666    }
667
668    /// Launches the node with the [`DebugNodeLauncher`].
669    ///
670    /// This is equivalent to [`WithLaunchContext::launch`], but will enable the debugging features,
671    /// if they are configured.
672    pub fn launch_with_debug_capabilities(
673        self,
674    ) -> <DebugNodeLauncher as LaunchNode<NodeBuilderWithComponents<T, CB, AO>>>::Future
675    where
676        T::Types: DebugNode<NodeAdapter<T, CB::Components>>,
677        DebugNodeLauncher: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
678    {
679        let Self { builder, task_executor } = self;
680
681        let engine_tree_config = builder.config.engine.tree_config();
682
683        let launcher = DebugNodeLauncher::new(EngineNodeLauncher::new(
684            task_executor,
685            builder.config.datadir(),
686            engine_tree_config,
687        ));
688        builder.launch_with(launcher)
689    }
690
691    /// Returns an [`EngineNodeLauncher`] that can be used to launch the node with engine API
692    /// support.
693    pub fn engine_api_launcher(&self) -> EngineNodeLauncher {
694        let engine_tree_config = self.builder.config.engine.tree_config();
695        EngineNodeLauncher::new(
696            self.task_executor.clone(),
697            self.builder.config.datadir(),
698            engine_tree_config,
699        )
700    }
701}
702
703/// Captures the necessary context for building the components of the node.
704pub struct BuilderContext<Node: FullNodeTypes> {
705    /// The current head of the blockchain at launch.
706    pub(crate) head: Head,
707    /// The configured provider to interact with the blockchain.
708    pub(crate) provider: Node::Provider,
709    /// The executor of the node.
710    pub(crate) executor: TaskExecutor,
711    /// Config container
712    pub(crate) config_container: WithConfigs<<Node::Types as NodeTypes>::ChainSpec>,
713}
714
715impl<Node: FullNodeTypes> BuilderContext<Node> {
716    /// Create a new instance of [`BuilderContext`]
717    pub const fn new(
718        head: Head,
719        provider: Node::Provider,
720        executor: TaskExecutor,
721        config_container: WithConfigs<<Node::Types as NodeTypes>::ChainSpec>,
722    ) -> Self {
723        Self { head, provider, executor, config_container }
724    }
725
726    /// Returns the configured provider to interact with the blockchain.
727    pub const fn provider(&self) -> &Node::Provider {
728        &self.provider
729    }
730
731    /// Returns the current head of the blockchain at launch.
732    pub const fn head(&self) -> Head {
733        self.head
734    }
735
736    /// Returns the config of the node.
737    pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
738        &self.config_container.config
739    }
740
741    /// Returns a mutable reference to the config of the node.
742    pub const fn config_mut(&mut self) -> &mut NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
743        &mut self.config_container.config
744    }
745
746    /// Returns the loaded reh.toml config.
747    pub const fn reth_config(&self) -> &reth_config::Config {
748        &self.config_container.toml_config
749    }
750
751    /// Returns the executor of the node.
752    ///
753    /// This can be used to execute async tasks or functions during the setup.
754    pub const fn task_executor(&self) -> &TaskExecutor {
755        &self.executor
756    }
757
758    /// Returns the chain spec of the node.
759    pub fn chain_spec(&self) -> Arc<<Node::Types as NodeTypes>::ChainSpec> {
760        self.provider().chain_spec()
761    }
762
763    /// Returns true if the node is configured as --dev
764    pub const fn is_dev(&self) -> bool {
765        self.config().dev.dev
766    }
767
768    /// Returns the transaction pool config of the node.
769    pub fn pool_config(&self) -> PoolConfig {
770        self.config().txpool.pool_config()
771    }
772
773    /// Loads `EnvKzgSettings::Default`.
774    pub const fn kzg_settings(&self) -> eyre::Result<EnvKzgSettings> {
775        Ok(EnvKzgSettings::Default)
776    }
777
778    /// Returns the config for payload building.
779    pub fn payload_builder_config(&self) -> impl PayloadBuilderConfig {
780        self.config().builder.clone()
781    }
782
783    /// Convenience function to start the network tasks.
784    ///
785    /// Spawns the configured network and associated tasks and returns the [`NetworkHandle`]
786    /// connected to that network.
787    pub fn start_network<N, Pool>(
788        &self,
789        builder: NetworkBuilder<(), (), N>,
790        pool: Pool,
791    ) -> NetworkHandle<N>
792    where
793        N: NetworkPrimitives,
794        Pool: TransactionPool<
795                Transaction: PoolTransaction<
796                    Consensus = N::BroadcastedTransaction,
797                    Pooled = N::PooledTransaction,
798                >,
799            > + Unpin
800            + 'static,
801        Node::Provider: BlockReaderFor<N>,
802    {
803        self.start_network_with(
804            builder,
805            pool,
806            self.config().network.transactions_manager_config(),
807            self.config().network.tx_propagation_policy,
808        )
809    }
810
811    /// Convenience function to start the network tasks.
812    ///
813    /// Accepts the config for the transaction task and the policy for propagation.
814    ///
815    /// Spawns the configured network and associated tasks and returns the [`NetworkHandle`]
816    /// connected to that network.
817    pub fn start_network_with<Pool, N, Policy>(
818        &self,
819        builder: NetworkBuilder<(), (), N>,
820        pool: Pool,
821        tx_config: TransactionsManagerConfig,
822        propagation_policy: Policy,
823    ) -> NetworkHandle<N>
824    where
825        N: NetworkPrimitives,
826        Pool: TransactionPool<
827                Transaction: PoolTransaction<
828                    Consensus = N::BroadcastedTransaction,
829                    Pooled = N::PooledTransaction,
830                >,
831            > + Unpin
832            + 'static,
833        Node::Provider: BlockReaderFor<N>,
834        Policy: TransactionPropagationPolicy<N>,
835    {
836        let (handle, network, txpool, eth) = builder
837            .transactions_with_policy(pool, tx_config, propagation_policy)
838            .request_handler(self.provider().clone())
839            .split_with_handle();
840
841        self.executor.spawn_critical("p2p txpool", Box::pin(txpool));
842        self.executor.spawn_critical("p2p eth request handler", Box::pin(eth));
843
844        let default_peers_path = self.config().datadir().known_peers();
845        let known_peers_file = self.config().network.persistent_peers_file(default_peers_path);
846        self.executor.spawn_critical_with_graceful_shutdown_signal(
847            "p2p network task",
848            |shutdown| {
849                Box::pin(network.run_until_graceful_shutdown(shutdown, |network| {
850                    if let Some(peers_file) = known_peers_file {
851                        let num_known_peers = network.num_known_peers();
852                        trace!(target: "reth::cli", peers_file=?peers_file, num_peers=%num_known_peers, "Saving current peers");
853                        match network.write_peers_to_file(peers_file.as_path()) {
854                            Ok(_) => {
855                                info!(target: "reth::cli", peers_file=?peers_file, "Wrote network peers to file");
856                            }
857                            Err(err) => {
858                                warn!(target: "reth::cli", %err, "Failed to write network peers to file");
859                            }
860                        }
861                    }
862                }))
863            },
864        );
865
866        handle
867    }
868
869    /// Get the network secret from the given data dir
870    fn network_secret(&self, data_dir: &ChainPath<DataDirPath>) -> eyre::Result<SecretKey> {
871        let secret_key = self.config().network.secret_key(data_dir.p2p_secret())?;
872        Ok(secret_key)
873    }
874
875    /// Builds the [`NetworkConfig`].
876    pub fn build_network_config<N>(
877        &self,
878        network_builder: NetworkConfigBuilder<N>,
879    ) -> NetworkConfig<Node::Provider, N>
880    where
881        N: NetworkPrimitives,
882        Node::Types: NodeTypes<ChainSpec: Hardforks>,
883    {
884        network_builder.build(self.provider.clone())
885    }
886}
887
888impl<Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>> BuilderContext<Node> {
889    /// Creates the [`NetworkBuilder`] for the node.
890    pub async fn network_builder<N>(&self) -> eyre::Result<NetworkBuilder<(), (), N>>
891    where
892        N: NetworkPrimitives,
893    {
894        let network_config = self.network_config()?;
895        let builder = NetworkManager::builder(network_config).await?;
896        Ok(builder)
897    }
898
899    /// Returns the default network config for the node.
900    pub fn network_config<N>(&self) -> eyre::Result<NetworkConfig<Node::Provider, N>>
901    where
902        N: NetworkPrimitives,
903    {
904        let network_builder = self.network_config_builder();
905        Ok(self.build_network_config(network_builder?))
906    }
907
908    /// Get the [`NetworkConfigBuilder`].
909    pub fn network_config_builder<N>(&self) -> eyre::Result<NetworkConfigBuilder<N>>
910    where
911        N: NetworkPrimitives,
912    {
913        let secret_key = self.network_secret(&self.config().datadir())?;
914        let default_peers_path = self.config().datadir().known_peers();
915        let builder = self
916            .config()
917            .network
918            .network_config(
919                self.reth_config(),
920                self.config().chain.clone(),
921                secret_key,
922                default_peers_path,
923            )
924            .with_task_executor(Box::new(self.executor.clone()))
925            .set_head(self.head);
926
927        Ok(builder)
928    }
929}
930
931impl<Node: FullNodeTypes> std::fmt::Debug for BuilderContext<Node> {
932    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
933        f.debug_struct("BuilderContext")
934            .field("head", &self.head)
935            .field("provider", &std::any::type_name::<Node::Provider>())
936            .field("executor", &self.executor)
937            .field("config", &self.config())
938            .finish()
939    }
940}