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::{noop::NoopConsensus, ConsensusError, FullConsensus};
11use reth_network::{types::NetPrimitivesFor, EthNetworkPrimitives, NetworkPrimitives};
12use reth_network_api::{noop::NoopNetwork, FullNetwork};
13use reth_node_api::{BlockTy, BodyTy, HeaderTy, NodeTypes, PrimitivesTy, ReceiptTy, TxTy};
14use reth_payload_builder::PayloadBuilderHandle;
15use reth_transaction_pool::{
16    noop::NoopTransactionPool, EthPoolTransaction, EthPooledTransaction, PoolPooledTx,
17    PoolTransaction, TransactionPool,
18};
19use std::{future::Future, marker::PhantomData};
20
21/// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation.
22///
23/// This type is stateful and captures the configuration of the node's components.
24///
25/// ## Component dependencies:
26///
27/// The components of the node depend on each other:
28/// - The payload builder service depends on the transaction pool.
29/// - The network depends on the transaction pool.
30///
31/// We distinguish between different kind of components:
32/// - Components that are standalone, such as the transaction pool.
33/// - Components that are spawned as a service, such as the payload builder service or the network.
34///
35/// ## Builder lifecycle:
36///
37/// First all standalone components are built. Then the service components are spawned.
38/// All component builders are captured in the builder state and will be consumed once the node is
39/// launched.
40#[derive(Debug)]
41pub struct ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> {
42    pool_builder: PoolB,
43    payload_builder: PayloadB,
44    network_builder: NetworkB,
45    executor_builder: ExecB,
46    consensus_builder: ConsB,
47    _marker: PhantomData<Node>,
48}
49
50impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
51    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
52{
53    /// Configures the node types.
54    pub fn node_types<Types>(
55        self,
56    ) -> ComponentsBuilder<Types, PoolB, PayloadB, NetworkB, ExecB, ConsB>
57    where
58        Types: FullNodeTypes,
59    {
60        let Self {
61            pool_builder,
62            payload_builder,
63            network_builder,
64            executor_builder: evm_builder,
65            consensus_builder,
66            _marker,
67        } = self;
68        ComponentsBuilder {
69            executor_builder: evm_builder,
70            pool_builder,
71            payload_builder,
72            network_builder,
73            consensus_builder,
74            _marker: Default::default(),
75        }
76    }
77
78    /// Apply a function to the pool builder.
79    pub fn map_pool(self, f: impl FnOnce(PoolB) -> PoolB) -> Self {
80        Self {
81            pool_builder: f(self.pool_builder),
82            payload_builder: self.payload_builder,
83            network_builder: self.network_builder,
84            executor_builder: self.executor_builder,
85            consensus_builder: self.consensus_builder,
86            _marker: self._marker,
87        }
88    }
89
90    /// Apply a function to the payload builder.
91    pub fn map_payload(self, f: impl FnOnce(PayloadB) -> PayloadB) -> Self {
92        Self {
93            pool_builder: self.pool_builder,
94            payload_builder: f(self.payload_builder),
95            network_builder: self.network_builder,
96            executor_builder: self.executor_builder,
97            consensus_builder: self.consensus_builder,
98            _marker: self._marker,
99        }
100    }
101
102    /// Apply a function to the network builder.
103    pub fn map_network(self, f: impl FnOnce(NetworkB) -> NetworkB) -> Self {
104        Self {
105            pool_builder: self.pool_builder,
106            payload_builder: self.payload_builder,
107            network_builder: f(self.network_builder),
108            executor_builder: self.executor_builder,
109            consensus_builder: self.consensus_builder,
110            _marker: self._marker,
111        }
112    }
113
114    /// Apply a function to the executor builder.
115    pub fn map_executor(self, f: impl FnOnce(ExecB) -> ExecB) -> Self {
116        Self {
117            pool_builder: self.pool_builder,
118            payload_builder: self.payload_builder,
119            network_builder: self.network_builder,
120            executor_builder: f(self.executor_builder),
121            consensus_builder: self.consensus_builder,
122            _marker: self._marker,
123        }
124    }
125
126    /// Apply a function to the consensus builder.
127    pub fn map_consensus(self, f: impl FnOnce(ConsB) -> ConsB) -> Self {
128        Self {
129            pool_builder: self.pool_builder,
130            payload_builder: self.payload_builder,
131            network_builder: self.network_builder,
132            executor_builder: self.executor_builder,
133            consensus_builder: f(self.consensus_builder),
134            _marker: self._marker,
135        }
136    }
137}
138
139impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
140    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
141where
142    Node: FullNodeTypes,
143{
144    /// Configures the pool builder.
145    ///
146    /// This accepts a [`PoolBuilder`] instance that will be used to create the node's transaction
147    /// pool.
148    pub fn pool<PB>(
149        self,
150        pool_builder: PB,
151    ) -> ComponentsBuilder<Node, PB, PayloadB, NetworkB, ExecB, ConsB>
152    where
153        PB: PoolBuilder<Node>,
154    {
155        let Self {
156            pool_builder: _,
157            payload_builder,
158            network_builder,
159            executor_builder: evm_builder,
160            consensus_builder,
161            _marker,
162        } = self;
163        ComponentsBuilder {
164            pool_builder,
165            payload_builder,
166            network_builder,
167            executor_builder: evm_builder,
168            consensus_builder,
169            _marker,
170        }
171    }
172
173    /// Sets [`NoopTransactionPoolBuilder`].
174    pub fn noop_pool<Tx>(
175        self,
176    ) -> ComponentsBuilder<Node, NoopTransactionPoolBuilder<Tx>, PayloadB, NetworkB, ExecB, ConsB>
177    {
178        ComponentsBuilder {
179            pool_builder: NoopTransactionPoolBuilder::<Tx>::default(),
180            payload_builder: self.payload_builder,
181            network_builder: self.network_builder,
182            executor_builder: self.executor_builder,
183            consensus_builder: self.consensus_builder,
184            _marker: self._marker,
185        }
186    }
187}
188
189impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
190    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
191where
192    Node: FullNodeTypes,
193    PoolB: PoolBuilder<Node>,
194{
195    /// Configures the network builder.
196    ///
197    /// This accepts a [`NetworkBuilder`] instance that will be used to create the node's network
198    /// stack.
199    pub fn network<NB>(
200        self,
201        network_builder: NB,
202    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NB, ExecB, ConsB>
203    where
204        NB: NetworkBuilder<Node, PoolB::Pool>,
205    {
206        let Self {
207            pool_builder,
208            payload_builder,
209            network_builder: _,
210            executor_builder: evm_builder,
211            consensus_builder,
212            _marker,
213        } = self;
214        ComponentsBuilder {
215            pool_builder,
216            payload_builder,
217            network_builder,
218            executor_builder: evm_builder,
219            consensus_builder,
220            _marker,
221        }
222    }
223
224    /// Configures the payload builder.
225    ///
226    /// This accepts a [`PayloadServiceBuilder`] instance that will be used to create the node's
227    /// payload builder service.
228    pub fn payload<PB>(
229        self,
230        payload_builder: PB,
231    ) -> ComponentsBuilder<Node, PoolB, PB, NetworkB, ExecB, ConsB>
232    where
233        ExecB: ExecutorBuilder<Node>,
234        PB: PayloadServiceBuilder<Node, PoolB::Pool, ExecB::EVM>,
235    {
236        let Self {
237            pool_builder,
238            payload_builder: _,
239            network_builder,
240            executor_builder: evm_builder,
241            consensus_builder,
242            _marker,
243        } = self;
244        ComponentsBuilder {
245            pool_builder,
246            payload_builder,
247            network_builder,
248            executor_builder: evm_builder,
249            consensus_builder,
250            _marker,
251        }
252    }
253
254    /// Configures the executor builder.
255    ///
256    /// This accepts a [`ExecutorBuilder`] instance that will be used to create the node's
257    /// components for execution.
258    pub fn executor<EB>(
259        self,
260        executor_builder: EB,
261    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, EB, ConsB>
262    where
263        EB: ExecutorBuilder<Node>,
264    {
265        let Self {
266            pool_builder,
267            payload_builder,
268            network_builder,
269            executor_builder: _,
270            consensus_builder,
271            _marker,
272        } = self;
273        ComponentsBuilder {
274            pool_builder,
275            payload_builder,
276            network_builder,
277            executor_builder,
278            consensus_builder,
279            _marker,
280        }
281    }
282
283    /// Configures the consensus builder.
284    ///
285    /// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's
286    /// components for consensus.
287    pub fn consensus<CB>(
288        self,
289        consensus_builder: CB,
290    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, CB>
291    where
292        CB: ConsensusBuilder<Node>,
293    {
294        let Self {
295            pool_builder,
296            payload_builder,
297            network_builder,
298            executor_builder,
299            consensus_builder: _,
300
301            _marker,
302        } = self;
303        ComponentsBuilder {
304            pool_builder,
305            payload_builder,
306            network_builder,
307            executor_builder,
308            consensus_builder,
309            _marker,
310        }
311    }
312
313    /// Sets [`NoopNetworkBuilder`].
314    pub fn noop_network<Net>(
315        self,
316    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NoopNetworkBuilder<Net>, ExecB, ConsB> {
317        ComponentsBuilder {
318            pool_builder: self.pool_builder,
319            payload_builder: self.payload_builder,
320            network_builder: NoopNetworkBuilder::<Net>::default(),
321            executor_builder: self.executor_builder,
322            consensus_builder: self.consensus_builder,
323            _marker: self._marker,
324        }
325    }
326
327    /// Sets [`NoopPayloadBuilder`].
328    pub fn noop_payload(
329        self,
330    ) -> ComponentsBuilder<Node, PoolB, NoopPayloadBuilder, NetworkB, ExecB, ConsB> {
331        ComponentsBuilder {
332            pool_builder: self.pool_builder,
333            payload_builder: NoopPayloadBuilder,
334            network_builder: self.network_builder,
335            executor_builder: self.executor_builder,
336            consensus_builder: self.consensus_builder,
337            _marker: self._marker,
338        }
339    }
340
341    /// Sets [`NoopConsensusBuilder`].
342    pub fn noop_consensus(
343        self,
344    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, NoopConsensusBuilder> {
345        ComponentsBuilder {
346            pool_builder: self.pool_builder,
347            payload_builder: self.payload_builder,
348            network_builder: self.network_builder,
349            executor_builder: self.executor_builder,
350            consensus_builder: NoopConsensusBuilder,
351            _marker: self._marker,
352        }
353    }
354}
355
356impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> NodeComponentsBuilder<Node>
357    for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
358where
359    Node: FullNodeTypes,
360    PoolB: PoolBuilder<Node, Pool: TransactionPool>,
361    NetworkB: NetworkBuilder<
362        Node,
363        PoolB::Pool,
364        Network: FullNetwork<
365            Primitives: NetPrimitivesFor<
366                PrimitivesTy<Node::Types>,
367                PooledTransaction = PoolPooledTx<PoolB::Pool>,
368            >,
369        >,
370    >,
371    PayloadB: PayloadServiceBuilder<Node, PoolB::Pool, ExecB::EVM>,
372    ExecB: ExecutorBuilder<Node>,
373    ConsB: ConsensusBuilder<Node>,
374{
375    type Components =
376        Components<Node, NetworkB::Network, PoolB::Pool, ExecB::EVM, ConsB::Consensus>;
377
378    async fn build_components(
379        self,
380        context: &BuilderContext<Node>,
381    ) -> eyre::Result<Self::Components> {
382        let Self {
383            pool_builder,
384            payload_builder,
385            network_builder,
386            executor_builder: evm_builder,
387            consensus_builder,
388            _marker,
389        } = self;
390
391        let evm_config = evm_builder.build_evm(context).await?;
392        let pool = pool_builder.build_pool(context).await?;
393        let network = network_builder.build_network(context, pool.clone()).await?;
394        let payload_builder_handle = payload_builder
395            .spawn_payload_builder_service(context, pool.clone(), evm_config.clone())
396            .await?;
397        let consensus = consensus_builder.build_consensus(context).await?;
398
399        Ok(Components {
400            transaction_pool: pool,
401            evm_config,
402            network,
403            payload_builder_handle,
404            consensus,
405        })
406    }
407}
408
409impl Default for ComponentsBuilder<(), (), (), (), (), ()> {
410    fn default() -> Self {
411        Self {
412            pool_builder: (),
413            payload_builder: (),
414            network_builder: (),
415            executor_builder: (),
416            consensus_builder: (),
417            _marker: Default::default(),
418        }
419    }
420}
421
422/// A type that configures all the customizable components of the node and knows how to build them.
423///
424/// Implementers of this trait are responsible for building all the components of the node: See
425/// [`NodeComponents`].
426///
427/// The [`ComponentsBuilder`] is a generic, general purpose implementation of this trait that can be
428/// used to customize certain components of the node using the builder pattern and defaults, e.g.
429/// Ethereum and Optimism.
430/// A type that's responsible for building the components of the node.
431pub trait NodeComponentsBuilder<Node: FullNodeTypes>: Send {
432    /// The components for the node with the given types
433    type Components: NodeComponents<Node>;
434
435    /// Consumes the type and returns the created components.
436    fn build_components(
437        self,
438        ctx: &BuilderContext<Node>,
439    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send;
440}
441
442impl<Node, Net, F, Fut, Pool, EVM, Cons> NodeComponentsBuilder<Node> for F
443where
444    Net: FullNetwork<
445        Primitives: NetPrimitivesFor<
446            PrimitivesTy<Node::Types>,
447            PooledTransaction = PoolPooledTx<Pool>,
448        >,
449    >,
450    Node: FullNodeTypes,
451    F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
452    Fut: Future<Output = eyre::Result<Components<Node, Net, Pool, EVM, Cons>>> + Send,
453    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
454        + Unpin
455        + 'static,
456    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
457    Cons:
458        FullConsensus<PrimitivesTy<Node::Types>, Error = ConsensusError> + Clone + Unpin + 'static,
459{
460    type Components = Components<Node, Net, Pool, EVM, Cons>;
461
462    fn build_components(
463        self,
464        ctx: &BuilderContext<Node>,
465    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send {
466        self(ctx)
467    }
468}
469
470/// Builds [`NoopTransactionPool`].
471#[derive(Debug, Clone)]
472pub struct NoopTransactionPoolBuilder<Tx = EthPooledTransaction>(PhantomData<Tx>);
473
474impl<N, Tx> PoolBuilder<N> for NoopTransactionPoolBuilder<Tx>
475where
476    N: FullNodeTypes,
477    Tx: EthPoolTransaction<Consensus = TxTy<N::Types>> + Unpin,
478{
479    type Pool = NoopTransactionPool<Tx>;
480
481    async fn build_pool(self, _ctx: &BuilderContext<N>) -> eyre::Result<Self::Pool> {
482        Ok(NoopTransactionPool::<Tx>::new())
483    }
484}
485
486impl<Tx> Default for NoopTransactionPoolBuilder<Tx> {
487    fn default() -> Self {
488        Self(PhantomData)
489    }
490}
491
492/// Builds [`NoopNetwork`].
493#[derive(Debug, Clone)]
494pub struct NoopNetworkBuilder<Net = EthNetworkPrimitives>(PhantomData<Net>);
495
496impl NoopNetworkBuilder {
497    /// Returns the instance with ethereum types.
498    pub fn eth() -> Self {
499        Self::default()
500    }
501}
502
503impl<N, Pool, Net> NetworkBuilder<N, Pool> for NoopNetworkBuilder<Net>
504where
505    N: FullNodeTypes,
506    Pool: TransactionPool,
507    Net: NetworkPrimitives<
508        BlockHeader = HeaderTy<N::Types>,
509        BlockBody = BodyTy<N::Types>,
510        Block = BlockTy<N::Types>,
511        Receipt = ReceiptTy<N::Types>,
512    >,
513{
514    type Network = NoopNetwork<Net>;
515
516    async fn build_network(
517        self,
518        _ctx: &BuilderContext<N>,
519        _pool: Pool,
520    ) -> eyre::Result<Self::Network> {
521        Ok(NoopNetwork::new())
522    }
523}
524
525impl<Net> Default for NoopNetworkBuilder<Net> {
526    fn default() -> Self {
527        Self(PhantomData)
528    }
529}
530
531/// Builds [`NoopConsensus`].
532#[derive(Debug, Clone, Default)]
533pub struct NoopConsensusBuilder;
534
535impl<N> ConsensusBuilder<N> for NoopConsensusBuilder
536where
537    N: FullNodeTypes,
538{
539    type Consensus = NoopConsensus;
540
541    async fn build_consensus(self, _ctx: &BuilderContext<N>) -> eyre::Result<Self::Consensus> {
542        Ok(NoopConsensus::default())
543    }
544}
545
546/// Builds [`PayloadBuilderHandle::noop`].
547#[derive(Debug, Clone, Default)]
548pub struct NoopPayloadBuilder;
549
550impl<N, Pool, EVM> PayloadServiceBuilder<N, Pool, EVM> for NoopPayloadBuilder
551where
552    N: FullNodeTypes,
553    Pool: TransactionPool,
554    EVM: ConfigureEvm<Primitives = PrimitivesTy<N::Types>> + 'static,
555{
556    async fn spawn_payload_builder_service(
557        self,
558        _ctx: &BuilderContext<N>,
559        _pool: Pool,
560        _evm_config: EVM,
561    ) -> eyre::Result<PayloadBuilderHandle<<N::Types as NodeTypes>::Payload>> {
562        Ok(PayloadBuilderHandle::<<N::Types as NodeTypes>::Payload>::noop())
563    }
564}