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