reth_node_builder/builder/
states.rs

1//! Node builder states and helper traits.
2//!
3//! Keeps track of the current state of the node builder.
4//!
5//! The node builder process is essentially a state machine that transitions through various states
6//! before the node can be launched.
7
8use crate::{
9    components::{NodeComponents, NodeComponentsBuilder},
10    hooks::NodeHooks,
11    launch::LaunchNode,
12    rpc::{RethRpcAddOns, RethRpcServerHandles, RpcContext},
13    AddOns, FullNode,
14};
15use reth_exex::ExExContext;
16use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypes, NodeTypesWithDB};
17use reth_node_core::node_config::NodeConfig;
18use reth_tasks::TaskExecutor;
19use std::{fmt, future::Future};
20
21/// A node builder that also has the configured types.
22pub struct NodeBuilderWithTypes<T: FullNodeTypes> {
23    /// All settings for how the node should be configured.
24    config: NodeConfig<<T::Types as NodeTypes>::ChainSpec>,
25    /// The configured database for the node.
26    adapter: NodeTypesAdapter<T>,
27}
28
29impl<T: FullNodeTypes> NodeBuilderWithTypes<T> {
30    /// Creates a new instance of the node builder with the given configuration and types.
31    pub const fn new(
32        config: NodeConfig<<T::Types as NodeTypes>::ChainSpec>,
33        database: <T::Types as NodeTypesWithDB>::DB,
34    ) -> Self {
35        Self { config, adapter: NodeTypesAdapter::new(database) }
36    }
37
38    /// Advances the state of the node builder to the next state where all components are configured
39    pub fn with_components<CB>(self, components_builder: CB) -> NodeBuilderWithComponents<T, CB, ()>
40    where
41        CB: NodeComponentsBuilder<T>,
42    {
43        let Self { config, adapter } = self;
44
45        NodeBuilderWithComponents {
46            config,
47            adapter,
48            components_builder,
49            add_ons: AddOns { hooks: NodeHooks::default(), exexs: Vec::new(), add_ons: () },
50        }
51    }
52}
53
54/// Container for the node's types and the database the node uses.
55pub struct NodeTypesAdapter<T: FullNodeTypes> {
56    /// The database type used by the node.
57    pub database: <T::Types as NodeTypesWithDB>::DB,
58}
59
60impl<T: FullNodeTypes> NodeTypesAdapter<T> {
61    /// Create a new adapter from the given node types.
62    pub(crate) const fn new(database: <T::Types as NodeTypesWithDB>::DB) -> Self {
63        Self { database }
64    }
65}
66
67impl<T: FullNodeTypes> fmt::Debug for NodeTypesAdapter<T> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.debug_struct("NodeTypesAdapter").field("db", &"...").field("types", &"...").finish()
70    }
71}
72
73/// Container for the node's types and the components and other internals that can be used by
74/// addons of the node.
75pub struct NodeAdapter<T: FullNodeTypes, C: NodeComponents<T>> {
76    /// The components of the node.
77    pub components: C,
78    /// The task executor for the node.
79    pub task_executor: TaskExecutor,
80    /// The provider of the node.
81    pub provider: T::Provider,
82}
83
84impl<T: FullNodeTypes, C: NodeComponents<T>> FullNodeTypes for NodeAdapter<T, C> {
85    type Types = T::Types;
86    type Provider = T::Provider;
87}
88
89impl<T: FullNodeTypes, C: NodeComponents<T>> FullNodeComponents for NodeAdapter<T, C> {
90    type Pool = C::Pool;
91    type Evm = C::Evm;
92    type Executor = C::Executor;
93    type Consensus = C::Consensus;
94    type Network = C::Network;
95    type PayloadBuilder = C::PayloadBuilder;
96
97    fn pool(&self) -> &Self::Pool {
98        self.components.pool()
99    }
100
101    fn evm_config(&self) -> &Self::Evm {
102        self.components.evm_config()
103    }
104
105    fn block_executor(&self) -> &Self::Executor {
106        self.components.block_executor()
107    }
108
109    fn consensus(&self) -> &Self::Consensus {
110        self.components.consensus()
111    }
112
113    fn network(&self) -> &Self::Network {
114        self.components.network()
115    }
116
117    fn payload_builder(&self) -> &Self::PayloadBuilder {
118        self.components.payload_builder()
119    }
120
121    fn provider(&self) -> &Self::Provider {
122        &self.provider
123    }
124
125    fn task_executor(&self) -> &TaskExecutor {
126        &self.task_executor
127    }
128}
129
130impl<T: FullNodeTypes, C: NodeComponents<T>> Clone for NodeAdapter<T, C> {
131    fn clone(&self) -> Self {
132        Self {
133            components: self.components.clone(),
134            task_executor: self.task_executor.clone(),
135            provider: self.provider.clone(),
136        }
137    }
138}
139
140/// A fully type configured node builder.
141///
142/// Supports adding additional addons to the node.
143pub struct NodeBuilderWithComponents<
144    T: FullNodeTypes,
145    CB: NodeComponentsBuilder<T>,
146    AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
147> {
148    /// All settings for how the node should be configured.
149    pub config: NodeConfig<<T::Types as NodeTypes>::ChainSpec>,
150    /// Adapter for the underlying node types and database
151    pub adapter: NodeTypesAdapter<T>,
152    /// container for type specific components
153    pub components_builder: CB,
154    /// Additional node extensions.
155    pub add_ons: AddOns<NodeAdapter<T, CB::Components>, AO>,
156}
157
158impl<T, CB> NodeBuilderWithComponents<T, CB, ()>
159where
160    T: FullNodeTypes,
161    CB: NodeComponentsBuilder<T>,
162{
163    /// Advances the state of the node builder to the next state where all customizable
164    /// [`NodeAddOns`] types are configured.
165    pub fn with_add_ons<AO>(self, add_ons: AO) -> NodeBuilderWithComponents<T, CB, AO>
166    where
167        AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
168    {
169        let Self { config, adapter, components_builder, .. } = self;
170
171        NodeBuilderWithComponents {
172            config,
173            adapter,
174            components_builder,
175            add_ons: AddOns { hooks: NodeHooks::default(), exexs: Vec::new(), add_ons },
176        }
177    }
178}
179
180impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
181where
182    T: FullNodeTypes,
183    CB: NodeComponentsBuilder<T>,
184    AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
185{
186    /// Sets the hook that is run once the node's components are initialized.
187    pub fn on_component_initialized<F>(mut self, hook: F) -> Self
188    where
189        F: FnOnce(NodeAdapter<T, CB::Components>) -> eyre::Result<()> + Send + 'static,
190    {
191        self.add_ons.hooks.set_on_component_initialized(hook);
192        self
193    }
194
195    /// Sets the hook that is run once the node has started.
196    pub fn on_node_started<F>(mut self, hook: F) -> Self
197    where
198        F: FnOnce(FullNode<NodeAdapter<T, CB::Components>, AO>) -> eyre::Result<()>
199            + Send
200            + 'static,
201    {
202        self.add_ons.hooks.set_on_node_started(hook);
203        self
204    }
205
206    /// Installs an `ExEx` (Execution Extension) in the node.
207    ///
208    /// # Note
209    ///
210    /// The `ExEx` ID must be unique.
211    pub fn install_exex<F, R, E>(mut self, exex_id: impl Into<String>, exex: F) -> Self
212    where
213        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
214        R: Future<Output = eyre::Result<E>> + Send,
215        E: Future<Output = eyre::Result<()>> + Send,
216    {
217        self.add_ons.exexs.push((exex_id.into(), Box::new(exex)));
218        self
219    }
220
221    /// Launches the node with the given closure.
222    pub fn launch_with_fn<L, R>(self, launcher: L) -> R
223    where
224        L: FnOnce(Self) -> R,
225    {
226        launcher(self)
227    }
228
229    /// Check that the builder can be launched
230    ///
231    /// This is useful when writing tests to ensure that the builder is configured correctly.
232    pub const fn check_launch(self) -> Self {
233        self
234    }
235
236    /// Modifies the addons with the given closure.
237    pub fn map_add_ons<F>(mut self, f: F) -> Self
238    where
239        F: FnOnce(AO) -> AO,
240    {
241        self.add_ons.add_ons = f(self.add_ons.add_ons);
242        self
243    }
244}
245
246impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
247where
248    T: FullNodeTypes,
249    CB: NodeComponentsBuilder<T>,
250    AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
251{
252    /// Launches the node with the given launcher.
253    pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
254    where
255        L: LaunchNode<Self>,
256    {
257        launcher.launch_node(self).await
258    }
259
260    /// Sets the hook that is run once the rpc server is started.
261    pub fn on_rpc_started<F>(self, hook: F) -> Self
262    where
263        F: FnOnce(
264                RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
265                RethRpcServerHandles,
266            ) -> eyre::Result<()>
267            + Send
268            + 'static,
269    {
270        self.map_add_ons(|mut add_ons| {
271            add_ons.hooks_mut().set_on_rpc_started(hook);
272            add_ons
273        })
274    }
275
276    /// Sets the hook that is run to configure the rpc modules.
277    pub fn extend_rpc_modules<F>(self, hook: F) -> Self
278    where
279        F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
280            + Send
281            + 'static,
282    {
283        self.map_add_ons(|mut add_ons| {
284            add_ons.hooks_mut().set_extend_rpc_modules(hook);
285            add_ons
286        })
287    }
288}