reth_node_builder/components/
builder.rs

1//! A generic [`NodeComponentsBuilder`]
2
3use crate::{
4    components::{
5        Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents,
6        PayloadServiceBuilder, PoolBuilder,
7    },
8    BuilderContext, ConfigureEvm, FullNodeTypes,
9};
10use reth_consensus::FullConsensus;
11use reth_evm::execute::BlockExecutorProvider;
12use reth_network::NetworkPrimitives;
13use reth_node_api::{BodyTy, HeaderTy, NodeTypes, NodeTypesWithEngine, TxTy};
14use reth_payload_builder::PayloadBuilderHandle;
15use reth_transaction_pool::{PoolTransaction, TransactionPool};
16use std::{future::Future, marker::PhantomData};
17
18/// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation.
19///
20/// This type is stateful and captures the configuration of the node's components.
21///
22/// ## Component dependencies:
23///
24/// The components of the node depend on each other:
25/// - The payload builder service depends on the transaction pool.
26/// - The network depends on the transaction pool.
27///
28/// We distinguish between different kind of components:
29/// - Components that are standalone, such as the transaction pool.
30/// - Components that are spawned as a service, such as the payload builder service or the network.
31///
32/// ## Builder lifecycle:
33///
34/// First all standalone components are built. Then the service components are spawned.
35/// All component builders are captured in the builder state and will be consumed once the node is
36/// launched.
37#[derive(Debug)]
38pub struct ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> {
39    pool_builder: PoolB,
40    payload_builder: PayloadB,
41    network_builder: NetworkB,
42    executor_builder: ExecB,
43    consensus_builder: ConsB,
44    _marker: PhantomData<Node>,
45}
46
47impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
48    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
49{
50    /// Configures the node types.
51    pub fn node_types<Types>(
52        self,
53    ) -> ComponentsBuilder<Types, PoolB, PayloadB, NetworkB, ExecB, ConsB>
54    where
55        Types: FullNodeTypes,
56    {
57        let Self {
58            pool_builder,
59            payload_builder,
60            network_builder,
61            executor_builder: evm_builder,
62            consensus_builder,
63            _marker,
64        } = self;
65        ComponentsBuilder {
66            executor_builder: evm_builder,
67            pool_builder,
68            payload_builder,
69            network_builder,
70            consensus_builder,
71            _marker: Default::default(),
72        }
73    }
74
75    /// Apply a function to the pool builder.
76    pub fn map_pool(self, f: impl FnOnce(PoolB) -> PoolB) -> Self {
77        Self {
78            pool_builder: f(self.pool_builder),
79            payload_builder: self.payload_builder,
80            network_builder: self.network_builder,
81            executor_builder: self.executor_builder,
82            consensus_builder: self.consensus_builder,
83            _marker: self._marker,
84        }
85    }
86
87    /// Apply a function to the payload builder.
88    pub fn map_payload(self, f: impl FnOnce(PayloadB) -> PayloadB) -> Self {
89        Self {
90            pool_builder: self.pool_builder,
91            payload_builder: f(self.payload_builder),
92            network_builder: self.network_builder,
93            executor_builder: self.executor_builder,
94            consensus_builder: self.consensus_builder,
95            _marker: self._marker,
96        }
97    }
98
99    /// Apply a function to the network builder.
100    pub fn map_network(self, f: impl FnOnce(NetworkB) -> NetworkB) -> Self {
101        Self {
102            pool_builder: self.pool_builder,
103            payload_builder: self.payload_builder,
104            network_builder: f(self.network_builder),
105            executor_builder: self.executor_builder,
106            consensus_builder: self.consensus_builder,
107            _marker: self._marker,
108        }
109    }
110
111    /// Apply a function to the executor builder.
112    pub fn map_executor(self, f: impl FnOnce(ExecB) -> ExecB) -> Self {
113        Self {
114            pool_builder: self.pool_builder,
115            payload_builder: self.payload_builder,
116            network_builder: self.network_builder,
117            executor_builder: f(self.executor_builder),
118            consensus_builder: self.consensus_builder,
119            _marker: self._marker,
120        }
121    }
122
123    /// Apply a function to the consensus builder.
124    pub fn map_consensus(self, f: impl FnOnce(ConsB) -> ConsB) -> Self {
125        Self {
126            pool_builder: self.pool_builder,
127            payload_builder: self.payload_builder,
128            network_builder: self.network_builder,
129            executor_builder: self.executor_builder,
130            consensus_builder: f(self.consensus_builder),
131            _marker: self._marker,
132        }
133    }
134}
135
136impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
137    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
138where
139    Node: FullNodeTypes,
140{
141    /// Configures the pool builder.
142    ///
143    /// This accepts a [`PoolBuilder`] instance that will be used to create the node's transaction
144    /// pool.
145    pub fn pool<PB>(
146        self,
147        pool_builder: PB,
148    ) -> ComponentsBuilder<Node, PB, PayloadB, NetworkB, ExecB, ConsB>
149    where
150        PB: PoolBuilder<Node>,
151    {
152        let Self {
153            pool_builder: _,
154            payload_builder,
155            network_builder,
156            executor_builder: evm_builder,
157            consensus_builder,
158            _marker,
159        } = self;
160        ComponentsBuilder {
161            pool_builder,
162            payload_builder,
163            network_builder,
164            executor_builder: evm_builder,
165            consensus_builder,
166            _marker,
167        }
168    }
169}
170
171impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
172    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
173where
174    Node: FullNodeTypes,
175    PoolB: PoolBuilder<Node>,
176{
177    /// Configures the network builder.
178    ///
179    /// This accepts a [`NetworkBuilder`] instance that will be used to create the node's network
180    /// stack.
181    pub fn network<NB>(
182        self,
183        network_builder: NB,
184    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NB, ExecB, ConsB>
185    where
186        NB: NetworkBuilder<Node, PoolB::Pool>,
187    {
188        let Self {
189            pool_builder,
190            payload_builder,
191            network_builder: _,
192            executor_builder: evm_builder,
193            consensus_builder,
194            _marker,
195        } = self;
196        ComponentsBuilder {
197            pool_builder,
198            payload_builder,
199            network_builder,
200            executor_builder: evm_builder,
201            consensus_builder,
202            _marker,
203        }
204    }
205
206    /// Configures the payload builder.
207    ///
208    /// This accepts a [`PayloadServiceBuilder`] instance that will be used to create the node's
209    /// payload builder service.
210    pub fn payload<PB>(
211        self,
212        payload_builder: PB,
213    ) -> ComponentsBuilder<Node, PoolB, PB, NetworkB, ExecB, ConsB>
214    where
215        PB: PayloadServiceBuilder<Node, PoolB::Pool>,
216    {
217        let Self {
218            pool_builder,
219            payload_builder: _,
220            network_builder,
221            executor_builder: evm_builder,
222            consensus_builder,
223            _marker,
224        } = self;
225        ComponentsBuilder {
226            pool_builder,
227            payload_builder,
228            network_builder,
229            executor_builder: evm_builder,
230            consensus_builder,
231            _marker,
232        }
233    }
234
235    /// Configures the executor builder.
236    ///
237    /// This accepts a [`ExecutorBuilder`] instance that will be used to create the node's
238    /// components for execution.
239    pub fn executor<EB>(
240        self,
241        executor_builder: EB,
242    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, EB, ConsB>
243    where
244        EB: ExecutorBuilder<Node>,
245    {
246        let Self {
247            pool_builder,
248            payload_builder,
249            network_builder,
250            executor_builder: _,
251            consensus_builder,
252            _marker,
253        } = self;
254        ComponentsBuilder {
255            pool_builder,
256            payload_builder,
257            network_builder,
258            executor_builder,
259            consensus_builder,
260            _marker,
261        }
262    }
263
264    /// Configures the consensus builder.
265    ///
266    /// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's
267    /// components for consensus.
268    pub fn consensus<CB>(
269        self,
270        consensus_builder: CB,
271    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, CB>
272    where
273        CB: ConsensusBuilder<Node>,
274    {
275        let Self {
276            pool_builder,
277            payload_builder,
278            network_builder,
279            executor_builder,
280            consensus_builder: _,
281
282            _marker,
283        } = self;
284        ComponentsBuilder {
285            pool_builder,
286            payload_builder,
287            network_builder,
288            executor_builder,
289            consensus_builder,
290            _marker,
291        }
292    }
293}
294
295impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> NodeComponentsBuilder<Node>
296    for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
297where
298    Node: FullNodeTypes,
299    PoolB: PoolBuilder<
300        Node,
301        Pool: TransactionPool<
302            Transaction: PoolTransaction<
303                Pooled = <NetworkB::Primitives as NetworkPrimitives>::PooledTransaction,
304            >,
305        >,
306    >,
307    NetworkB: NetworkBuilder<
308        Node,
309        PoolB::Pool,
310        Primitives: NetworkPrimitives<
311            BlockHeader = HeaderTy<Node::Types>,
312            BlockBody = BodyTy<Node::Types>,
313        >,
314    >,
315    PayloadB: PayloadServiceBuilder<Node, PoolB::Pool>,
316    ExecB: ExecutorBuilder<Node>,
317    ConsB: ConsensusBuilder<Node>,
318{
319    type Components = Components<
320        Node,
321        NetworkB::Primitives,
322        PoolB::Pool,
323        ExecB::EVM,
324        ExecB::Executor,
325        ConsB::Consensus,
326    >;
327
328    async fn build_components(
329        self,
330        context: &BuilderContext<Node>,
331    ) -> eyre::Result<Self::Components> {
332        let Self {
333            pool_builder,
334            payload_builder,
335            network_builder,
336            executor_builder: evm_builder,
337            consensus_builder,
338            _marker,
339        } = self;
340
341        let (evm_config, executor) = evm_builder.build_evm(context).await?;
342        let pool = pool_builder.build_pool(context).await?;
343        let network = network_builder.build_network(context, pool.clone()).await?;
344        let payload_builder = payload_builder.spawn_payload_service(context, pool.clone()).await?;
345        let consensus = consensus_builder.build_consensus(context).await?;
346
347        Ok(Components {
348            transaction_pool: pool,
349            evm_config,
350            network,
351            payload_builder,
352            executor,
353            consensus,
354        })
355    }
356}
357
358impl Default for ComponentsBuilder<(), (), (), (), (), ()> {
359    fn default() -> Self {
360        Self {
361            pool_builder: (),
362            payload_builder: (),
363            network_builder: (),
364            executor_builder: (),
365            consensus_builder: (),
366            _marker: Default::default(),
367        }
368    }
369}
370
371/// A type that configures all the customizable components of the node and knows how to build them.
372///
373/// Implementers of this trait are responsible for building all the components of the node: See
374/// [`NodeComponents`].
375///
376/// The [`ComponentsBuilder`] is a generic, general purpose implementation of this trait that can be
377/// used to customize certain components of the node using the builder pattern and defaults, e.g.
378/// Ethereum and Optimism.
379/// A type that's responsible for building the components of the node.
380pub trait NodeComponentsBuilder<Node: FullNodeTypes>: Send {
381    /// The components for the node with the given types
382    type Components: NodeComponents<
383        Node,
384        PayloadBuilder = PayloadBuilderHandle<<Node::Types as NodeTypesWithEngine>::Engine>,
385    >;
386
387    /// Consumes the type and returns the created components.
388    fn build_components(
389        self,
390        ctx: &BuilderContext<Node>,
391    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send;
392}
393
394impl<Node, N, F, Fut, Pool, EVM, Executor, Cons> NodeComponentsBuilder<Node> for F
395where
396    N: NetworkPrimitives<BlockHeader = HeaderTy<Node::Types>, BlockBody = BodyTy<Node::Types>>,
397    Node: FullNodeTypes,
398    F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
399    Fut: Future<Output = eyre::Result<Components<Node, N, Pool, EVM, Executor, Cons>>> + Send,
400    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
401        + Unpin
402        + 'static,
403    EVM: ConfigureEvm<Header = HeaderTy<Node::Types>, Transaction = TxTy<Node::Types>>,
404    Executor: BlockExecutorProvider<Primitives = <Node::Types as NodeTypes>::Primitives>,
405    Cons: FullConsensus<<Node::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static,
406{
407    type Components = Components<Node, N, Pool, EVM, Executor, Cons>;
408
409    fn build_components(
410        self,
411        ctx: &BuilderContext<Node>,
412    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send {
413        self(ctx)
414    }
415}