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