//! A generic [`NodeComponentsBuilder`] use std::{future::Future, marker::PhantomData}; use reth_consensus::Consensus; use reth_evm::execute::BlockExecutorProvider; use reth_transaction_pool::TransactionPool; use crate::{ components::{ Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents, PayloadServiceBuilder, PoolBuilder, }, BuilderContext, ConfigureEvm, FullNodeTypes, }; /// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation. /// /// This type is stateful and captures the configuration of the node's components. /// /// ## Component dependencies: /// /// The components of the node depend on each other: /// - The payload builder service depends on the transaction pool. /// - The network depends on the transaction pool. /// /// We distinguish between different kind of components: /// - Components that are standalone, such as the transaction pool. /// - Components that are spawned as a service, such as the payload builder service or the network. /// /// ## Builder lifecycle: /// /// First all standalone components are built. Then the service components are spawned. /// All component builders are captured in the builder state and will be consumed once the node is /// launched. #[derive(Debug)] pub struct ComponentsBuilder { pool_builder: PoolB, payload_builder: PayloadB, network_builder: NetworkB, executor_builder: ExecB, consensus_builder: ConsB, _marker: PhantomData, } impl ComponentsBuilder { /// Configures the node types. pub fn node_types( self, ) -> ComponentsBuilder where Types: FullNodeTypes, { let Self { pool_builder, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } = self; ComponentsBuilder { executor_builder: evm_builder, pool_builder, payload_builder, network_builder, consensus_builder, _marker: Default::default(), } } /// Apply a function to the pool builder. pub fn map_pool(self, f: impl FnOnce(PoolB) -> PoolB) -> Self { Self { pool_builder: f(self.pool_builder), payload_builder: self.payload_builder, network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, _marker: self._marker, } } /// Apply a function to the payload builder. pub fn map_payload(self, f: impl FnOnce(PayloadB) -> PayloadB) -> Self { Self { pool_builder: self.pool_builder, payload_builder: f(self.payload_builder), network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, _marker: self._marker, } } /// Apply a function to the network builder. pub fn map_network(self, f: impl FnOnce(NetworkB) -> NetworkB) -> Self { Self { pool_builder: self.pool_builder, payload_builder: self.payload_builder, network_builder: f(self.network_builder), executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, _marker: self._marker, } } /// Apply a function to the executor builder. pub fn map_executor(self, f: impl FnOnce(ExecB) -> ExecB) -> Self { Self { pool_builder: self.pool_builder, payload_builder: self.payload_builder, network_builder: self.network_builder, executor_builder: f(self.executor_builder), consensus_builder: self.consensus_builder, _marker: self._marker, } } /// Apply a function to the consensus builder. pub fn map_consensus(self, f: impl FnOnce(ConsB) -> ConsB) -> Self { Self { pool_builder: self.pool_builder, payload_builder: self.payload_builder, network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: f(self.consensus_builder), _marker: self._marker, } } } impl ComponentsBuilder where Node: FullNodeTypes, { /// Configures the pool builder. /// /// This accepts a [`PoolBuilder`] instance that will be used to create the node's transaction /// pool. pub fn pool( self, pool_builder: PB, ) -> ComponentsBuilder where PB: PoolBuilder, { let Self { pool_builder: _, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } = self; ComponentsBuilder { pool_builder, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } } } impl ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, { /// Configures the network builder. /// /// This accepts a [`NetworkBuilder`] instance that will be used to create the node's network /// stack. pub fn network( self, network_builder: NB, ) -> ComponentsBuilder where NB: NetworkBuilder, { let Self { pool_builder, payload_builder, network_builder: _, executor_builder: evm_builder, consensus_builder, _marker, } = self; ComponentsBuilder { pool_builder, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } } /// Configures the payload builder. /// /// This accepts a [`PayloadServiceBuilder`] instance that will be used to create the node's /// payload builder service. pub fn payload( self, payload_builder: PB, ) -> ComponentsBuilder where PB: PayloadServiceBuilder, { let Self { pool_builder, payload_builder: _, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } = self; ComponentsBuilder { pool_builder, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } } /// Configures the executor builder. /// /// This accepts a [`ExecutorBuilder`] instance that will be used to create the node's /// components for execution. pub fn executor( self, executor_builder: EB, ) -> ComponentsBuilder where EB: ExecutorBuilder, { let Self { pool_builder, payload_builder, network_builder, executor_builder: _, consensus_builder, _marker, } = self; ComponentsBuilder { pool_builder, payload_builder, network_builder, executor_builder, consensus_builder, _marker, } } /// Configures the consensus builder. /// /// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's /// components for consensus. pub fn consensus( self, consensus_builder: CB, ) -> ComponentsBuilder where CB: ConsensusBuilder, { let Self { pool_builder, payload_builder, network_builder, executor_builder, consensus_builder: _, _marker, } = self; ComponentsBuilder { pool_builder, payload_builder, network_builder, executor_builder, consensus_builder, _marker, } } } impl NodeComponentsBuilder for ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, NetworkB: NetworkBuilder, PayloadB: PayloadServiceBuilder, ExecB: ExecutorBuilder, ConsB: ConsensusBuilder, { type Components = Components; async fn build_components( self, context: &BuilderContext, ) -> eyre::Result { let Self { pool_builder, payload_builder, network_builder, executor_builder: evm_builder, consensus_builder, _marker, } = self; let (evm_config, executor) = evm_builder.build_evm(context).await?; let pool = pool_builder.build_pool(context).await?; let network = network_builder.build_network(context, pool.clone()).await?; let payload_builder = payload_builder.spawn_payload_service(context, pool.clone()).await?; let consensus = consensus_builder.build_consensus(context).await?; Ok(Components { transaction_pool: pool, evm_config, network, payload_builder, executor, consensus, }) } } impl Default for ComponentsBuilder<(), (), (), (), (), ()> { fn default() -> Self { Self { pool_builder: (), payload_builder: (), network_builder: (), executor_builder: (), consensus_builder: (), _marker: Default::default(), } } } /// A type that configures all the customizable components of the node and knows how to build them. /// /// Implementers of this trait are responsible for building all the components of the node: See /// [`NodeComponents`]. /// /// The [`ComponentsBuilder`] is a generic, general purpose implementation of this trait that can be /// used to customize certain components of the node using the builder pattern and defaults, e.g. /// Ethereum and Optimism. /// A type that's responsible for building the components of the node. pub trait NodeComponentsBuilder: Send { /// The components for the node with the given types type Components: NodeComponents; /// Consumes the type and returns the created components. fn build_components( self, ctx: &BuilderContext, ) -> impl Future> + Send; } impl NodeComponentsBuilder for F where Node: FullNodeTypes, F: FnOnce(&BuilderContext) -> Fut + Send, Fut: Future>> + Send, Pool: TransactionPool + Unpin + 'static, EVM: ConfigureEvm, Executor: BlockExecutorProvider, Cons: Consensus + Clone + Unpin + 'static, { type Components = Components; fn build_components( self, ctx: &BuilderContext, ) -> impl Future> + Send { self(ctx) } }