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::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    /// Apply a function to the builder
165    pub fn apply<F>(self, f: F) -> Self
166    where
167        F: FnOnce(Self) -> Self,
168    {
169        f(self)
170    }
171
172    /// Apply a function to the builder, if the condition is `true`.
173    pub fn apply_if<F>(self, cond: bool, f: F) -> Self
174    where
175        F: FnOnce(Self) -> Self,
176    {
177        if cond {
178            f(self)
179        } else {
180            self
181        }
182    }
183}
184
185impl<DB, ChainSpec> NodeBuilder<DB, ChainSpec> {
186    /// Returns a reference to the node builder's config.
187    pub const fn config(&self) -> &NodeConfig<ChainSpec> {
188        &self.config
189    }
190
191    /// Returns a mutable reference to the node builder's config.
192    pub const fn config_mut(&mut self) -> &mut NodeConfig<ChainSpec> {
193        &mut self.config
194    }
195}
196
197impl<DB, ChainSpec: EthChainSpec> NodeBuilder<DB, ChainSpec> {
198    /// Configures the underlying database that the node will use.
199    pub fn with_database<D>(self, database: D) -> NodeBuilder<D, ChainSpec> {
200        NodeBuilder { config: self.config, database }
201    }
202
203    /// Preconfigure the builder with the context to launch the node.
204    ///
205    /// This provides the task executor and the data directory for the node.
206    pub const fn with_launch_context(self, task_executor: TaskExecutor) -> WithLaunchContext<Self> {
207        WithLaunchContext { builder: self, task_executor }
208    }
209
210    /// Creates an _ephemeral_ preconfigured node for testing purposes.
211    #[cfg(feature = "test-utils")]
212    pub fn testing_node(
213        mut self,
214        task_executor: TaskExecutor,
215    ) -> WithLaunchContext<
216        NodeBuilder<Arc<reth_db::test_utils::TempDatabase<reth_db::DatabaseEnv>>, ChainSpec>,
217    > {
218        let path = reth_node_core::dirs::MaybePlatformPath::<DataDirPath>::from(
219            reth_db::test_utils::tempdir_path(),
220        );
221        self.config = self.config.with_datadir_args(reth_node_core::args::DatadirArgs {
222            datadir: path.clone(),
223            ..Default::default()
224        });
225
226        let data_dir =
227            path.unwrap_or_chain_default(self.config.chain.chain(), self.config.datadir.clone());
228
229        let db = reth_db::test_utils::create_test_rw_db_with_path(data_dir.db());
230
231        WithLaunchContext { builder: self.with_database(db), task_executor }
232    }
233}
234
235impl<DB, ChainSpec> NodeBuilder<DB, ChainSpec>
236where
237    DB: Database + DatabaseMetrics + Clone + Unpin + 'static,
238    ChainSpec: EthChainSpec + EthereumHardforks,
239{
240    /// Configures the types of the node.
241    pub fn with_types<T>(self) -> NodeBuilderWithTypes<RethFullAdapter<DB, T>>
242    where
243        T: NodeTypes<ChainSpec = ChainSpec> + NodeTypesForProvider,
244    {
245        self.with_types_and_provider()
246    }
247
248    /// Configures the types of the node and the provider type that will be used by the node.
249    pub fn with_types_and_provider<T, P>(
250        self,
251    ) -> NodeBuilderWithTypes<FullNodeTypesAdapter<T, DB, P>>
252    where
253        T: NodeTypes<ChainSpec = ChainSpec> + NodeTypesForProvider,
254        P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
255    {
256        NodeBuilderWithTypes::new(self.config, self.database)
257    }
258
259    /// Preconfigures the node with a specific node implementation.
260    ///
261    /// This is a convenience method that sets the node's types and components in one call.
262    pub fn node<N>(
263        self,
264        node: N,
265    ) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>
266    where
267        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
268    {
269        self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
270    }
271}
272
273/// A [`NodeBuilder`] with it's launch context already configured.
274///
275/// This exposes the same methods as [`NodeBuilder`] but with the launch context already configured,
276/// See [`WithLaunchContext::launch`]
277pub struct WithLaunchContext<Builder> {
278    builder: Builder,
279    task_executor: TaskExecutor,
280}
281
282impl<Builder> WithLaunchContext<Builder> {
283    /// Returns a reference to the task executor.
284    pub const fn task_executor(&self) -> &TaskExecutor {
285        &self.task_executor
286    }
287}
288
289impl<DB, ChainSpec> WithLaunchContext<NodeBuilder<DB, ChainSpec>> {
290    /// Returns a reference to the node builder's config.
291    pub const fn config(&self) -> &NodeConfig<ChainSpec> {
292        self.builder.config()
293    }
294}
295
296impl<DB, ChainSpec> WithLaunchContext<NodeBuilder<DB, ChainSpec>>
297where
298    DB: Database + DatabaseMetrics + Clone + Unpin + 'static,
299    ChainSpec: EthChainSpec + EthereumHardforks,
300{
301    /// Configures the types of the node.
302    pub fn with_types<T>(self) -> WithLaunchContext<NodeBuilderWithTypes<RethFullAdapter<DB, T>>>
303    where
304        T: NodeTypes<ChainSpec = ChainSpec> + NodeTypesForProvider,
305    {
306        WithLaunchContext { builder: self.builder.with_types(), task_executor: self.task_executor }
307    }
308
309    /// Configures the types of the node and the provider type that will be used by the node.
310    pub fn with_types_and_provider<T, P>(
311        self,
312    ) -> WithLaunchContext<NodeBuilderWithTypes<FullNodeTypesAdapter<T, DB, P>>>
313    where
314        T: NodeTypes<ChainSpec = ChainSpec> + NodeTypesForProvider,
315        P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
316    {
317        WithLaunchContext {
318            builder: self.builder.with_types_and_provider(),
319            task_executor: self.task_executor,
320        }
321    }
322
323    /// Preconfigures the node with a specific node implementation.
324    ///
325    /// This is a convenience method that sets the node's types and components in one call.
326    pub fn node<N>(
327        self,
328        node: N,
329    ) -> WithLaunchContext<
330        NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
331    >
332    where
333        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
334    {
335        self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
336    }
337
338    /// Launches a preconfigured [Node]
339    ///
340    /// This bootstraps the node internals, creates all the components with the given [Node]
341    ///
342    /// Returns a [`NodeHandle`](crate::NodeHandle) that can be used to interact with the node.
343    pub async fn launch_node<N>(
344        self,
345        node: N,
346    ) -> eyre::Result<
347        <EngineNodeLauncher as LaunchNode<
348            NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
349        >>::Node,
350    >
351    where
352        N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
353        N::AddOns: RethRpcAddOns<
354            NodeAdapter<
355                RethFullAdapter<DB, N>,
356                <N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
357            >,
358        >,
359        N::Primitives: FullNodePrimitives,
360        EngineNodeLauncher: LaunchNode<
361            NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
362        >,
363    {
364        self.node(node).launch().await
365    }
366}
367
368impl<T: FullNodeTypes> WithLaunchContext<NodeBuilderWithTypes<T>> {
369    /// Advances the state of the node builder to the next state where all components are configured
370    pub fn with_components<CB>(
371        self,
372        components_builder: CB,
373    ) -> WithLaunchContext<NodeBuilderWithComponents<T, CB, ()>>
374    where
375        CB: NodeComponentsBuilder<T>,
376    {
377        WithLaunchContext {
378            builder: self.builder.with_components(components_builder),
379            task_executor: self.task_executor,
380        }
381    }
382}
383
384impl<T, CB> WithLaunchContext<NodeBuilderWithComponents<T, CB, ()>>
385where
386    T: FullNodeTypes,
387    CB: NodeComponentsBuilder<T>,
388{
389    /// Advances the state of the node builder to the next state where all customizable
390    /// [`NodeAddOns`] types are configured.
391    pub fn with_add_ons<AO>(
392        self,
393        add_ons: AO,
394    ) -> WithLaunchContext<NodeBuilderWithComponents<T, CB, AO>>
395    where
396        AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
397    {
398        WithLaunchContext {
399            builder: self.builder.with_add_ons(add_ons),
400            task_executor: self.task_executor,
401        }
402    }
403}
404
405impl<T, CB, AO> WithLaunchContext<NodeBuilderWithComponents<T, CB, AO>>
406where
407    T: FullNodeTypes,
408    CB: NodeComponentsBuilder<T>,
409    AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
410{
411    /// Returns a reference to the node builder's config.
412    pub const fn config(&self) -> &NodeConfig<<T::Types as NodeTypes>::ChainSpec> {
413        &self.builder.config
414    }
415
416    /// Apply a function to the builder
417    pub fn apply<F>(self, f: F) -> Self
418    where
419        F: FnOnce(Self) -> Self,
420    {
421        f(self)
422    }
423
424    /// Apply a function to the builder, if the condition is `true`.
425    pub fn apply_if<F>(self, cond: bool, f: F) -> Self
426    where
427        F: FnOnce(Self) -> Self,
428    {
429        if cond {
430            f(self)
431        } else {
432            self
433        }
434    }
435
436    /// Sets the hook that is run once the node's components are initialized.
437    pub fn on_component_initialized<F>(self, hook: F) -> Self
438    where
439        F: FnOnce(NodeAdapter<T, CB::Components>) -> eyre::Result<()> + Send + 'static,
440    {
441        Self {
442            builder: self.builder.on_component_initialized(hook),
443            task_executor: self.task_executor,
444        }
445    }
446
447    /// Sets the hook that is run once the node has started.
448    pub fn on_node_started<F>(self, hook: F) -> Self
449    where
450        F: FnOnce(FullNode<NodeAdapter<T, CB::Components>, AO>) -> eyre::Result<()>
451            + Send
452            + 'static,
453    {
454        Self { builder: self.builder.on_node_started(hook), task_executor: self.task_executor }
455    }
456
457    /// Modifies the addons with the given closure.
458    pub fn map_add_ons<F>(self, f: F) -> Self
459    where
460        F: FnOnce(AO) -> AO,
461    {
462        Self { builder: self.builder.map_add_ons(f), task_executor: self.task_executor }
463    }
464
465    /// Sets the hook that is run once the rpc server is started.
466    pub fn on_rpc_started<F>(self, hook: F) -> Self
467    where
468        F: FnOnce(
469                RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
470                RethRpcServerHandles,
471            ) -> eyre::Result<()>
472            + Send
473            + 'static,
474    {
475        Self { builder: self.builder.on_rpc_started(hook), task_executor: self.task_executor }
476    }
477
478    /// Sets the hook that is run to configure the rpc modules.
479    pub fn extend_rpc_modules<F>(self, hook: F) -> Self
480    where
481        F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
482            + Send
483            + 'static,
484    {
485        Self { builder: self.builder.extend_rpc_modules(hook), task_executor: self.task_executor }
486    }
487
488    /// Installs an `ExEx` (Execution Extension) in the node.
489    ///
490    /// # Note
491    ///
492    /// The `ExEx` ID must be unique.
493    pub fn install_exex<F, R, E>(self, exex_id: impl Into<String>, exex: F) -> Self
494    where
495        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
496        R: Future<Output = eyre::Result<E>> + Send,
497        E: Future<Output = eyre::Result<()>> + Send,
498    {
499        Self {
500            builder: self.builder.install_exex(exex_id, exex),
501            task_executor: self.task_executor,
502        }
503    }
504
505    /// Installs an `ExEx` (Execution Extension) in the node if the condition is true.
506    ///
507    /// # Note
508    ///
509    /// The `ExEx` ID must be unique.
510    pub fn install_exex_if<F, R, E>(self, cond: bool, exex_id: impl Into<String>, exex: F) -> Self
511    where
512        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
513        R: Future<Output = eyre::Result<E>> + Send,
514        E: Future<Output = eyre::Result<()>> + Send,
515    {
516        if cond {
517            self.install_exex(exex_id, exex)
518        } else {
519            self
520        }
521    }
522
523    /// Launches the node with the given launcher.
524    pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
525    where
526        L: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
527    {
528        launcher.launch_node(self.builder).await
529    }
530
531    /// Launches the node with the given closure.
532    pub fn launch_with_fn<L, R>(self, launcher: L) -> R
533    where
534        L: FnOnce(Self) -> R,
535    {
536        launcher(self)
537    }
538
539    /// Check that the builder can be launched
540    ///
541    /// This is useful when writing tests to ensure that the builder is configured correctly.
542    pub const fn check_launch(self) -> Self {
543        self
544    }
545
546    /// Launches the node with the [`EngineNodeLauncher`] that sets up engine API consensus and rpc
547    pub async fn launch(
548        self,
549    ) -> eyre::Result<<EngineNodeLauncher as LaunchNode<NodeBuilderWithComponents<T, CB, AO>>>::Node>
550    where
551        EngineNodeLauncher: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
552    {
553        let Self { builder, task_executor } = self;
554
555        let engine_tree_config = builder.config.engine.tree_config();
556
557        let launcher =
558            EngineNodeLauncher::new(task_executor, builder.config.datadir(), engine_tree_config);
559        builder.launch_with(launcher).await
560    }
561
562    /// Launches the node with the [`DebugNodeLauncher`].
563    ///
564    /// This is equivalent to [`WithLaunchContext::launch`], but will enable the debugging features,
565    /// if they are configured.
566    pub async fn launch_with_debug_capabilities(
567        self,
568    ) -> eyre::Result<<DebugNodeLauncher as LaunchNode<NodeBuilderWithComponents<T, CB, AO>>>::Node>
569    where
570        T::Types: DebugNode<NodeAdapter<T, CB::Components>>,
571        DebugNodeLauncher: LaunchNode<NodeBuilderWithComponents<T, CB, AO>>,
572    {
573        let Self { builder, task_executor } = self;
574
575        let engine_tree_config = builder.config.engine.tree_config();
576
577        let launcher = DebugNodeLauncher::new(EngineNodeLauncher::new(
578            task_executor,
579            builder.config.datadir(),
580            engine_tree_config,
581        ));
582        builder.launch_with(launcher).await
583    }
584}
585
586/// Captures the necessary context for building the components of the node.
587pub struct BuilderContext<Node: FullNodeTypes> {
588    /// The current head of the blockchain at launch.
589    pub(crate) head: Head,
590    /// The configured provider to interact with the blockchain.
591    pub(crate) provider: Node::Provider,
592    /// The executor of the node.
593    pub(crate) executor: TaskExecutor,
594    /// Config container
595    pub(crate) config_container: WithConfigs<<Node::Types as NodeTypes>::ChainSpec>,
596}
597
598impl<Node: FullNodeTypes> BuilderContext<Node> {
599    /// Create a new instance of [`BuilderContext`]
600    pub const fn new(
601        head: Head,
602        provider: Node::Provider,
603        executor: TaskExecutor,
604        config_container: WithConfigs<<Node::Types as NodeTypes>::ChainSpec>,
605    ) -> Self {
606        Self { head, provider, executor, config_container }
607    }
608
609    /// Returns the configured provider to interact with the blockchain.
610    pub const fn provider(&self) -> &Node::Provider {
611        &self.provider
612    }
613
614    /// Returns the current head of the blockchain at launch.
615    pub const fn head(&self) -> Head {
616        self.head
617    }
618
619    /// Returns the config of the node.
620    pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
621        &self.config_container.config
622    }
623
624    /// Returns the loaded reh.toml config.
625    pub const fn reth_config(&self) -> &reth_config::Config {
626        &self.config_container.toml_config
627    }
628
629    /// Returns the executor of the node.
630    ///
631    /// This can be used to execute async tasks or functions during the setup.
632    pub const fn task_executor(&self) -> &TaskExecutor {
633        &self.executor
634    }
635
636    /// Returns the chain spec of the node.
637    pub fn chain_spec(&self) -> Arc<<Node::Types as NodeTypes>::ChainSpec> {
638        self.provider().chain_spec()
639    }
640
641    /// Returns true if the node is configured as --dev
642    pub const fn is_dev(&self) -> bool {
643        self.config().dev.dev
644    }
645
646    /// Returns the transaction pool config of the node.
647    pub fn pool_config(&self) -> PoolConfig {
648        self.config().txpool.pool_config()
649    }
650
651    /// Loads `EnvKzgSettings::Default`.
652    pub const fn kzg_settings(&self) -> eyre::Result<EnvKzgSettings> {
653        Ok(EnvKzgSettings::Default)
654    }
655
656    /// Returns the config for payload building.
657    pub fn payload_builder_config(&self) -> impl PayloadBuilderConfig {
658        self.config().builder.clone()
659    }
660
661    /// Convenience function to start the network tasks.
662    ///
663    /// Spawns the configured network and associated tasks and returns the [`NetworkHandle`]
664    /// connected to that network.
665    pub fn start_network<N, Pool>(
666        &self,
667        builder: NetworkBuilder<(), (), N>,
668        pool: Pool,
669    ) -> NetworkHandle<N>
670    where
671        N: NetworkPrimitives,
672        Pool: TransactionPool<
673                Transaction: PoolTransaction<
674                    Consensus = N::BroadcastedTransaction,
675                    Pooled = N::PooledTransaction,
676                >,
677            > + Unpin
678            + 'static,
679        Node::Provider: BlockReaderFor<N>,
680    {
681        self.start_network_with(
682            builder,
683            pool,
684            self.config().network.transactions_manager_config(),
685            self.config().network.tx_propagation_policy,
686        )
687    }
688
689    /// Convenience function to start the network tasks.
690    ///
691    /// Accepts the config for the transaction task and the policy for propagation.
692    ///
693    /// Spawns the configured network and associated tasks and returns the [`NetworkHandle`]
694    /// connected to that network.
695    pub fn start_network_with<Pool, N, Policy>(
696        &self,
697        builder: NetworkBuilder<(), (), N>,
698        pool: Pool,
699        tx_config: TransactionsManagerConfig,
700        propagation_policy: Policy,
701    ) -> NetworkHandle<N>
702    where
703        N: NetworkPrimitives,
704        Pool: TransactionPool<
705                Transaction: PoolTransaction<
706                    Consensus = N::BroadcastedTransaction,
707                    Pooled = N::PooledTransaction,
708                >,
709            > + Unpin
710            + 'static,
711        Node::Provider: BlockReaderFor<N>,
712        Policy: TransactionPropagationPolicy,
713    {
714        let (handle, network, txpool, eth) = builder
715            .transactions_with_policy(pool, tx_config, propagation_policy)
716            .request_handler(self.provider().clone())
717            .split_with_handle();
718
719        self.executor.spawn_critical("p2p txpool", txpool);
720        self.executor.spawn_critical("p2p eth request handler", eth);
721
722        let default_peers_path = self.config().datadir().known_peers();
723        let known_peers_file = self.config().network.persistent_peers_file(default_peers_path);
724        self.executor.spawn_critical_with_graceful_shutdown_signal(
725            "p2p network task",
726            |shutdown| {
727                network.run_until_graceful_shutdown(shutdown, |network| {
728                    if let Some(peers_file) = known_peers_file {
729                        let num_known_peers = network.num_known_peers();
730                        trace!(target: "reth::cli", peers_file=?peers_file, num_peers=%num_known_peers, "Saving current peers");
731                        match network.write_peers_to_file(peers_file.as_path()) {
732                            Ok(_) => {
733                                info!(target: "reth::cli", peers_file=?peers_file, "Wrote network peers to file");
734                            }
735                            Err(err) => {
736                                warn!(target: "reth::cli", %err, "Failed to write network peers to file");
737                            }
738                        }
739                    }
740                })
741            },
742        );
743
744        handle
745    }
746
747    /// Get the network secret from the given data dir
748    fn network_secret(&self, data_dir: &ChainPath<DataDirPath>) -> eyre::Result<SecretKey> {
749        let network_secret_path =
750            self.config().network.p2p_secret_key.clone().unwrap_or_else(|| data_dir.p2p_secret());
751        let secret_key = get_secret_key(&network_secret_path)?;
752        Ok(secret_key)
753    }
754
755    /// Builds the [`NetworkConfig`].
756    pub fn build_network_config<N>(
757        &self,
758        network_builder: NetworkConfigBuilder<N>,
759    ) -> NetworkConfig<Node::Provider, N>
760    where
761        N: NetworkPrimitives,
762        Node::Types: NodeTypes<ChainSpec: Hardforks>,
763    {
764        network_builder.build(self.provider.clone())
765    }
766}
767
768impl<Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>> BuilderContext<Node> {
769    /// Creates the [`NetworkBuilder`] for the node.
770    pub async fn network_builder<N>(&self) -> eyre::Result<NetworkBuilder<(), (), N>>
771    where
772        N: NetworkPrimitives,
773    {
774        let network_config = self.network_config()?;
775        let builder = NetworkManager::builder(network_config).await?;
776        Ok(builder)
777    }
778
779    /// Returns the default network config for the node.
780    pub fn network_config<N>(&self) -> eyre::Result<NetworkConfig<Node::Provider, N>>
781    where
782        N: NetworkPrimitives,
783    {
784        let network_builder = self.network_config_builder();
785        Ok(self.build_network_config(network_builder?))
786    }
787
788    /// Get the [`NetworkConfigBuilder`].
789    pub fn network_config_builder<N>(&self) -> eyre::Result<NetworkConfigBuilder<N>>
790    where
791        N: NetworkPrimitives,
792    {
793        let secret_key = self.network_secret(&self.config().datadir())?;
794        let default_peers_path = self.config().datadir().known_peers();
795        let builder = self
796            .config()
797            .network
798            .network_config(
799                self.reth_config(),
800                self.config().chain.clone(),
801                secret_key,
802                default_peers_path,
803            )
804            .with_task_executor(Box::new(self.executor.clone()))
805            .set_head(self.head);
806
807        Ok(builder)
808    }
809}
810
811impl<Node: FullNodeTypes> std::fmt::Debug for BuilderContext<Node> {
812    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
813        f.debug_struct("BuilderContext")
814            .field("head", &self.head)
815            .field("provider", &std::any::type_name::<Node::Provider>())
816            .field("executor", &self.executor)
817            .field("config", &self.config())
818            .finish()
819    }
820}