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