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