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};
17use reth_node_core::node_config::NodeConfig;
18use reth_tasks::TaskExecutor;
19use std::{fmt, fmt::Debug, 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::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::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::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.
75#[derive(Debug)]
76pub struct NodeAdapter<T: FullNodeTypes, C: NodeComponents<T>> {
77    /// The components of the node.
78    pub components: C,
79    /// The task executor for the node.
80    pub task_executor: TaskExecutor,
81    /// The provider of the node.
82    pub provider: T::Provider,
83}
84
85impl<T: FullNodeTypes, C: NodeComponents<T>> FullNodeTypes for NodeAdapter<T, C> {
86    type Types = T::Types;
87    type DB = T::DB;
88    type Provider = T::Provider;
89}
90
91impl<T: FullNodeTypes, C: NodeComponents<T>> FullNodeComponents for NodeAdapter<T, C> {
92    type Pool = C::Pool;
93    type Evm = C::Evm;
94    type Executor = C::Executor;
95    type Consensus = C::Consensus;
96    type Network = C::Network;
97
98    fn pool(&self) -> &Self::Pool {
99        self.components.pool()
100    }
101
102    fn evm_config(&self) -> &Self::Evm {
103        self.components.evm_config()
104    }
105
106    fn block_executor(&self) -> &Self::Executor {
107        self.components.block_executor()
108    }
109
110    fn consensus(&self) -> &Self::Consensus {
111        self.components.consensus()
112    }
113
114    fn network(&self) -> &Self::Network {
115        self.components.network()
116    }
117
118    fn payload_builder_handle(
119        &self,
120    ) -> &reth_payload_builder::PayloadBuilderHandle<
121        <Self::Types as reth_node_api::NodeTypes>::Payload,
122    > {
123        self.components.payload_builder_handle()
124    }
125
126    fn provider(&self) -> &Self::Provider {
127        &self.provider
128    }
129
130    fn task_executor(&self) -> &TaskExecutor {
131        &self.task_executor
132    }
133}
134
135impl<T: FullNodeTypes, C: NodeComponents<T>> Clone for NodeAdapter<T, C> {
136    fn clone(&self) -> Self {
137        Self {
138            components: self.components.clone(),
139            task_executor: self.task_executor.clone(),
140            provider: self.provider.clone(),
141        }
142    }
143}
144
145/// A fully type configured node builder.
146///
147/// Supports adding additional addons to the node.
148pub struct NodeBuilderWithComponents<
149    T: FullNodeTypes,
150    CB: NodeComponentsBuilder<T>,
151    AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
152> {
153    /// All settings for how the node should be configured.
154    pub config: NodeConfig<<T::Types as NodeTypes>::ChainSpec>,
155    /// Adapter for the underlying node types and database
156    pub adapter: NodeTypesAdapter<T>,
157    /// container for type specific components
158    pub components_builder: CB,
159    /// Additional node extensions.
160    pub add_ons: AddOns<NodeAdapter<T, CB::Components>, AO>,
161}
162
163impl<T, CB> NodeBuilderWithComponents<T, CB, ()>
164where
165    T: FullNodeTypes,
166    CB: NodeComponentsBuilder<T>,
167{
168    /// Advances the state of the node builder to the next state where all customizable
169    /// [`NodeAddOns`] types are configured.
170    pub fn with_add_ons<AO>(self, add_ons: AO) -> NodeBuilderWithComponents<T, CB, AO>
171    where
172        AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
173    {
174        let Self { config, adapter, components_builder, .. } = self;
175
176        NodeBuilderWithComponents {
177            config,
178            adapter,
179            components_builder,
180            add_ons: AddOns { hooks: NodeHooks::default(), exexs: Vec::new(), add_ons },
181        }
182    }
183}
184
185impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
186where
187    T: FullNodeTypes,
188    CB: NodeComponentsBuilder<T>,
189    AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
190{
191    /// Sets the hook that is run once the node's components are initialized.
192    pub fn on_component_initialized<F>(mut self, hook: F) -> Self
193    where
194        F: FnOnce(NodeAdapter<T, CB::Components>) -> eyre::Result<()> + Send + 'static,
195    {
196        self.add_ons.hooks.set_on_component_initialized(hook);
197        self
198    }
199
200    /// Sets the hook that is run once the node has started.
201    pub fn on_node_started<F>(mut self, hook: F) -> Self
202    where
203        F: FnOnce(FullNode<NodeAdapter<T, CB::Components>, AO>) -> eyre::Result<()>
204            + Send
205            + 'static,
206    {
207        self.add_ons.hooks.set_on_node_started(hook);
208        self
209    }
210
211    /// Installs an `ExEx` (Execution Extension) in the node.
212    ///
213    /// # Note
214    ///
215    /// The `ExEx` ID must be unique.
216    pub fn install_exex<F, R, E>(mut self, exex_id: impl Into<String>, exex: F) -> Self
217    where
218        F: FnOnce(ExExContext<NodeAdapter<T, CB::Components>>) -> R + Send + 'static,
219        R: Future<Output = eyre::Result<E>> + Send,
220        E: Future<Output = eyre::Result<()>> + Send,
221    {
222        self.add_ons.exexs.push((exex_id.into(), Box::new(exex)));
223        self
224    }
225
226    /// Launches the node with the given closure.
227    pub fn launch_with_fn<L, R>(self, launcher: L) -> R
228    where
229        L: FnOnce(Self) -> R,
230    {
231        launcher(self)
232    }
233
234    /// Check that the builder can be launched
235    ///
236    /// This is useful when writing tests to ensure that the builder is configured correctly.
237    pub const fn check_launch(self) -> Self {
238        self
239    }
240
241    /// Modifies the addons with the given closure.
242    pub fn map_add_ons<F>(mut self, f: F) -> Self
243    where
244        F: FnOnce(AO) -> AO,
245    {
246        self.add_ons.add_ons = f(self.add_ons.add_ons);
247        self
248    }
249}
250
251impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
252where
253    T: FullNodeTypes,
254    CB: NodeComponentsBuilder<T>,
255    AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
256{
257    /// Launches the node with the given launcher.
258    pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
259    where
260        L: LaunchNode<Self>,
261    {
262        launcher.launch_node(self).await
263    }
264
265    /// Sets the hook that is run once the rpc server is started.
266    pub fn on_rpc_started<F>(self, hook: F) -> Self
267    where
268        F: FnOnce(
269                RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
270                RethRpcServerHandles,
271            ) -> eyre::Result<()>
272            + Send
273            + 'static,
274    {
275        self.map_add_ons(|mut add_ons| {
276            add_ons.hooks_mut().set_on_rpc_started(hook);
277            add_ons
278        })
279    }
280
281    /// Sets the hook that is run to configure the rpc modules.
282    pub fn extend_rpc_modules<F>(self, hook: F) -> Self
283    where
284        F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
285            + Send
286            + 'static,
287    {
288        self.map_add_ons(|mut add_ons| {
289            add_ons.hooks_mut().set_extend_rpc_modules(hook);
290            add_ons
291        })
292    }
293}