Skip to main content

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, 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,
66            consensus_builder,
67            _marker,
68        } = self;
69        ComponentsBuilder {
70            executor_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        let Self {
154            pool_builder: _,
155            payload_builder,
156            network_builder,
157            executor_builder,
158            consensus_builder,
159            _marker,
160        } = self;
161        ComponentsBuilder {
162            pool_builder,
163            payload_builder,
164            network_builder,
165            executor_builder,
166            consensus_builder,
167            _marker,
168        }
169    }
170
171    /// Sets [`NoopTransactionPoolBuilder`].
172    pub fn noop_pool<Tx>(
173        self,
174    ) -> ComponentsBuilder<Node, NoopTransactionPoolBuilder<Tx>, PayloadB, NetworkB, ExecB, ConsB>
175    {
176        ComponentsBuilder {
177            pool_builder: NoopTransactionPoolBuilder::<Tx>::default(),
178            payload_builder: self.payload_builder,
179            network_builder: self.network_builder,
180            executor_builder: self.executor_builder,
181            consensus_builder: self.consensus_builder,
182            _marker: self._marker,
183        }
184    }
185
186    /// Configures the executor builder.
187    ///
188    /// This accepts a [`ExecutorBuilder`] instance that will be used to create the node's
189    /// components for execution.
190    pub fn executor<EB>(
191        self,
192        executor_builder: EB,
193    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, EB, ConsB>
194    where
195        EB: ExecutorBuilder<Node>,
196    {
197        let Self {
198            pool_builder,
199            payload_builder,
200            network_builder,
201            executor_builder: _,
202            consensus_builder,
203            _marker,
204        } = self;
205        ComponentsBuilder {
206            pool_builder,
207            payload_builder,
208            network_builder,
209            executor_builder,
210            consensus_builder,
211            _marker,
212        }
213    }
214
215    /// Configures the consensus builder.
216    ///
217    /// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's
218    /// components for consensus.
219    pub fn consensus<CB>(
220        self,
221        consensus_builder: CB,
222    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, CB>
223    where
224        CB: ConsensusBuilder<Node>,
225    {
226        let Self {
227            pool_builder,
228            payload_builder,
229            network_builder,
230            executor_builder,
231            consensus_builder: _,
232            _marker,
233        } = self;
234        ComponentsBuilder {
235            pool_builder,
236            payload_builder,
237            network_builder,
238            executor_builder,
239            consensus_builder,
240            _marker,
241        }
242    }
243}
244
245impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
246    ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
247where
248    Node: FullNodeTypes,
249    ExecB: ExecutorBuilder<Node>,
250    PoolB: PoolBuilder<Node, ExecB::EVM>,
251{
252    /// Configures the network builder.
253    ///
254    /// This accepts a [`NetworkBuilder`] instance that will be used to create the node's network
255    /// stack.
256    pub fn network<NB>(
257        self,
258        network_builder: NB,
259    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NB, ExecB, ConsB>
260    where
261        NB: NetworkBuilder<Node, PoolB::Pool>,
262    {
263        let Self {
264            pool_builder,
265            payload_builder,
266            network_builder: _,
267            executor_builder,
268            consensus_builder,
269            _marker,
270        } = self;
271        ComponentsBuilder {
272            pool_builder,
273            payload_builder,
274            network_builder,
275            executor_builder,
276            consensus_builder,
277            _marker,
278        }
279    }
280
281    /// Configures the payload builder.
282    ///
283    /// This accepts a [`PayloadServiceBuilder`] instance that will be used to create the node's
284    /// payload builder service.
285    pub fn payload<PB>(
286        self,
287        payload_builder: PB,
288    ) -> ComponentsBuilder<Node, PoolB, PB, NetworkB, ExecB, ConsB>
289    where
290        PB: PayloadServiceBuilder<Node, PoolB::Pool, ExecB::EVM>,
291    {
292        let Self {
293            pool_builder,
294            payload_builder: _,
295            network_builder,
296            executor_builder,
297            consensus_builder,
298            _marker,
299        } = self;
300        ComponentsBuilder {
301            pool_builder,
302            payload_builder,
303            network_builder,
304            executor_builder,
305            consensus_builder,
306            _marker,
307        }
308    }
309
310    /// Sets [`NoopNetworkBuilder`].
311    pub fn noop_network<Net>(
312        self,
313    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NoopNetworkBuilder<Net>, ExecB, ConsB> {
314        ComponentsBuilder {
315            pool_builder: self.pool_builder,
316            payload_builder: self.payload_builder,
317            network_builder: NoopNetworkBuilder::<Net>::default(),
318            executor_builder: self.executor_builder,
319            consensus_builder: self.consensus_builder,
320            _marker: self._marker,
321        }
322    }
323
324    /// Sets [`NoopPayloadBuilder`].
325    pub fn noop_payload(
326        self,
327    ) -> ComponentsBuilder<Node, PoolB, NoopPayloadBuilder, NetworkB, ExecB, ConsB> {
328        ComponentsBuilder {
329            pool_builder: self.pool_builder,
330            payload_builder: NoopPayloadBuilder,
331            network_builder: self.network_builder,
332            executor_builder: self.executor_builder,
333            consensus_builder: self.consensus_builder,
334            _marker: self._marker,
335        }
336    }
337
338    /// Sets [`NoopConsensusBuilder`].
339    pub fn noop_consensus(
340        self,
341    ) -> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, NoopConsensusBuilder> {
342        ComponentsBuilder {
343            pool_builder: self.pool_builder,
344            payload_builder: self.payload_builder,
345            network_builder: self.network_builder,
346            executor_builder: self.executor_builder,
347            consensus_builder: NoopConsensusBuilder,
348            _marker: self._marker,
349        }
350    }
351}
352
353impl<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB> NodeComponentsBuilder<Node>
354    for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB, ExecB, ConsB>
355where
356    Node: FullNodeTypes,
357    PoolB: PoolBuilder<Node, ExecB::EVM, Pool: TransactionPool>,
358    NetworkB: NetworkBuilder<
359        Node,
360        PoolB::Pool,
361        Network: FullNetwork<
362            Primitives: NetPrimitivesFor<
363                PrimitivesTy<Node::Types>,
364                PooledTransaction = PoolPooledTx<PoolB::Pool>,
365            >,
366        >,
367    >,
368    PayloadB: PayloadServiceBuilder<Node, PoolB::Pool, ExecB::EVM>,
369    ExecB: ExecutorBuilder<Node>,
370    ConsB: ConsensusBuilder<Node>,
371{
372    type Components =
373        Components<Node, NetworkB::Network, PoolB::Pool, ExecB::EVM, ConsB::Consensus>;
374
375    async fn build_components(
376        self,
377        context: &BuilderContext<Node>,
378    ) -> eyre::Result<Self::Components> {
379        let Self {
380            pool_builder,
381            payload_builder,
382            network_builder,
383            executor_builder,
384            consensus_builder,
385            _marker,
386        } = self;
387
388        let evm_config = executor_builder.build_evm(context).await?;
389        let pool = pool_builder.build_pool(context, evm_config.clone()).await?;
390        let network = network_builder.build_network(context, pool.clone()).await?;
391        let payload_builder_handle = payload_builder
392            .spawn_payload_builder_service(context, pool.clone(), evm_config.clone())
393            .await?;
394        let consensus = consensus_builder.build_consensus(context).await?;
395
396        Ok(Components {
397            transaction_pool: pool,
398            evm_config,
399            network,
400            payload_builder_handle,
401            consensus,
402        })
403    }
404}
405
406impl Default for ComponentsBuilder<(), (), (), (), (), ()> {
407    fn default() -> Self {
408        Self {
409            pool_builder: (),
410            payload_builder: (),
411            network_builder: (),
412            executor_builder: (),
413            consensus_builder: (),
414            _marker: Default::default(),
415        }
416    }
417}
418
419/// A type that configures all the customizable components of the node and knows how to build them.
420///
421/// Implementers of this trait are responsible for building all the components of the node: See
422/// [`NodeComponents`].
423///
424/// The [`ComponentsBuilder`] is a generic, general purpose implementation of this trait that can be
425/// used to customize certain components of the node using the builder pattern and defaults, e.g.
426/// Ethereum and Optimism.
427/// A type that's responsible for building the components of the node.
428pub trait NodeComponentsBuilder<Node: FullNodeTypes>: Send {
429    /// The components for the node with the given types
430    type Components: NodeComponents<Node>;
431
432    /// Consumes the type and returns the created components.
433    fn build_components(
434        self,
435        ctx: &BuilderContext<Node>,
436    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send;
437}
438
439impl<Node, Net, F, Fut, Pool, EVM, Cons> NodeComponentsBuilder<Node> for F
440where
441    Net: FullNetwork<
442        Primitives: NetPrimitivesFor<
443            PrimitivesTy<Node::Types>,
444            PooledTransaction = PoolPooledTx<Pool>,
445        >,
446    >,
447    Node: FullNodeTypes,
448    F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
449    Fut: Future<Output = eyre::Result<Components<Node, Net, Pool, EVM, Cons>>> + Send,
450    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
451        + Unpin
452        + 'static,
453    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
454    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
455{
456    type Components = Components<Node, Net, Pool, EVM, Cons>;
457
458    fn build_components(
459        self,
460        ctx: &BuilderContext<Node>,
461    ) -> impl Future<Output = eyre::Result<Self::Components>> + Send {
462        self(ctx)
463    }
464}
465
466/// Builds [`NoopTransactionPool`].
467#[derive(Debug, Clone)]
468pub struct NoopTransactionPoolBuilder<Tx = EthPooledTransaction>(PhantomData<Tx>);
469
470impl<N, Tx, Evm> PoolBuilder<N, Evm> for NoopTransactionPoolBuilder<Tx>
471where
472    N: FullNodeTypes,
473    Tx: EthPoolTransaction<Consensus = TxTy<N::Types>> + Unpin,
474    Evm: Send,
475{
476    type Pool = NoopTransactionPool<Tx>;
477
478    async fn build_pool(
479        self,
480        _ctx: &BuilderContext<N>,
481        _evm_config: Evm,
482    ) -> 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}