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