diff --git a/crates/blockchain-tree/src/noop.rs b/crates/blockchain-tree/src/noop.rs index 9fa820255..bb99f9b55 100644 --- a/crates/blockchain-tree/src/noop.rs +++ b/crates/blockchain-tree/src/noop.rs @@ -27,6 +27,15 @@ pub struct NoopBlockchainTree { pub canon_state_notification_sender: Option, } +impl NoopBlockchainTree { + /// Create a new NoopBlockchainTree with a canon state notification sender. + pub fn with_canon_state_notifications( + canon_state_notification_sender: CanonStateNotificationSender, + ) -> Self { + Self { canon_state_notification_sender: Some(canon_state_notification_sender) } + } +} + impl BlockchainTreeEngine for NoopBlockchainTree { fn buffer_block(&self, _block: SealedBlockWithSenders) -> Result<(), InsertBlockError> { Ok(()) diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 78a76e54c..9179abc33 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -80,7 +80,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// This represents the set of methods used to configure the EVM's environment before block /// execution. -pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone { +pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { /// The type of the transaction metadata that should be used to fill fields in the transaction /// environment. /// diff --git a/crates/node-ethereum/src/node.rs b/crates/node-ethereum/src/node.rs index 5a1a03554..4f52027b4 100644 --- a/crates/node-ethereum/src/node.rs +++ b/crates/node-ethereum/src/node.rs @@ -4,7 +4,9 @@ use crate::{EthEngineTypes, EthEvmConfig}; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_network::NetworkHandle; use reth_node_builder::{ - components::{ComponentsBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder}, + components::{ + ComponentsBuilder, ExecutorBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder, + }, node::{FullNodeTypes, NodeTypes}, BuilderContext, Node, PayloadBuilderConfig, }; @@ -23,8 +25,13 @@ pub struct EthereumNode; impl EthereumNode { /// Returns a [ComponentsBuilder] configured for a regular Ethereum node. - pub fn components( - ) -> ComponentsBuilder + pub fn components() -> ComponentsBuilder< + Node, + EthereumPoolBuilder, + EthereumPayloadBuilder, + EthereumNetworkBuilder, + EthereumExecutorBuilder, + > where Node: FullNodeTypes, { @@ -33,31 +40,48 @@ impl EthereumNode { .pool(EthereumPoolBuilder::default()) .payload(EthereumPayloadBuilder::default()) .network(EthereumNetworkBuilder::default()) + .executor(EthereumExecutorBuilder::default()) } } impl NodeTypes for EthereumNode { type Primitives = (); type Engine = EthEngineTypes; - type Evm = EthEvmConfig; - - fn evm_config(&self) -> Self::Evm { - EthEvmConfig::default() - } } impl Node for EthereumNode where N: FullNodeTypes, { - type ComponentsBuilder = - ComponentsBuilder; + type ComponentsBuilder = ComponentsBuilder< + N, + EthereumPoolBuilder, + EthereumPayloadBuilder, + EthereumNetworkBuilder, + EthereumExecutorBuilder, + >; fn components_builder(self) -> Self::ComponentsBuilder { Self::components() } } +/// A regular ethereum evm and executor builder. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct EthereumExecutorBuilder; + +impl ExecutorBuilder for EthereumExecutorBuilder +where + Node: FullNodeTypes, +{ + type EVM = EthEvmConfig; + + async fn build_evm(self, _ctx: &BuilderContext) -> eyre::Result { + Ok(EthEvmConfig::default()) + } +} + /// A basic ethereum transaction pool. /// /// This contains various settings that can be configured and take precedence over the node's diff --git a/crates/node-ethereum/tests/it/builder.rs b/crates/node-ethereum/tests/it/builder.rs index 1f4579236..b48e58679 100644 --- a/crates/node-ethereum/tests/it/builder.rs +++ b/crates/node-ethereum/tests/it/builder.rs @@ -13,7 +13,7 @@ fn test_basic_setup() { let msg = "On components".to_string(); let _builder = NodeBuilder::new(config) .with_database(db) - .with_types(EthereumNode::default()) + .with_types::() .with_components(EthereumNode::components()) .on_component_initialized(move |ctx| { let _provider = ctx.provider(); diff --git a/crates/node-ethereum/tests/it/exex.rs b/crates/node-ethereum/tests/it/exex.rs index bbab6d9dc..80366ba23 100644 --- a/crates/node-ethereum/tests/it/exex.rs +++ b/crates/node-ethereum/tests/it/exex.rs @@ -31,7 +31,7 @@ fn basic_exex() { let db = create_test_rw_db(); let _builder = NodeBuilder::new(config) .with_database(db) - .with_types(EthereumNode::default()) + .with_types::() .with_components(EthereumNode::components()) .install_exex("dummy", move |ctx| future::ok(DummyExEx { _ctx: ctx })) .check_launch(); diff --git a/crates/node/api/src/node.rs b/crates/node/api/src/node.rs index 2eb14011f..0a76f7504 100644 --- a/crates/node/api/src/node.rs +++ b/crates/node/api/src/node.rs @@ -1,4 +1,4 @@ -//! Traits for configuring a node +//! Traits for configuring a node. use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes}; use reth_db::{ @@ -15,21 +15,20 @@ use std::marker::PhantomData; /// The type that configures the essential types of an ethereum like node. /// /// This includes the primitive types of a node, the engine API types for communication with the -/// consensus layer, and the EVM configuration type for setting up the Ethereum Virtual Machine. +/// consensus layer. +/// +/// This trait is intended to be stateless and only define the types of the node. pub trait NodeTypes: Send + Sync + 'static { /// The node's primitive types, defining basic operations and structures. type Primitives: NodePrimitives; /// The node's engine types, defining the interaction with the consensus engine. type Engine: EngineTypes; - /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine. - type Evm: ConfigureEvm; - - /// Returns the node's evm config. - fn evm_config(&self) -> Self::Evm; } /// A helper trait that is downstream of the [NodeTypes] trait and adds stateful components to the /// node. +/// +/// Its types are configured by node internally and are not intended to be user configurable. pub trait FullNodeTypes: NodeTypes + 'static { /// Underlying database type used by the node to store and retrieve data. type DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static; @@ -41,7 +40,7 @@ pub trait FullNodeTypes: NodeTypes + 'static { #[derive(Debug)] pub struct FullNodeTypesAdapter { /// An instance of the user configured node types. - pub types: Types, + pub types: PhantomData, /// The database type used by the node. pub db: PhantomData, /// The provider type used by the node. @@ -49,9 +48,15 @@ pub struct FullNodeTypesAdapter { } impl FullNodeTypesAdapter { - /// Create a new adapter from the given node types. - pub fn new(types: Types) -> Self { - Self { types, db: Default::default(), provider: Default::default() } + /// Create a new adapter with the configured types. + pub fn new() -> Self { + Self { types: Default::default(), db: Default::default(), provider: Default::default() } + } +} + +impl Default for FullNodeTypesAdapter { + fn default() -> Self { + Self::new() } } @@ -63,11 +68,6 @@ where { type Primitives = Types::Primitives; type Engine = Types::Engine; - type Evm = Types::Evm; - - fn evm_config(&self) -> Self::Evm { - self.types.evm_config() - } } impl FullNodeTypes for FullNodeTypesAdapter @@ -85,9 +85,15 @@ pub trait FullNodeComponents: FullNodeTypes + 'static { /// The transaction pool of the node. type Pool: TransactionPool + Unpin; + /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine. + type Evm: ConfigureEvm; + /// Returns the transaction pool of the node. fn pool(&self) -> &Self::Pool; + /// Returns the node's evm config. + fn evm_config(&self) -> &Self::Evm; + /// Returns the provider of the node. fn provider(&self) -> &Self::Provider; diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index 7f898ca21..815b13858 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -50,10 +50,10 @@ pub type RethFullAdapter = FullNodeTypesAdapter = FullNodeTypesAdapter = FullNodeTypesAdapter { @@ -187,12 +188,11 @@ where DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, { /// Configures the types of the node. - pub fn with_types(self, types: T) -> NodeBuilderWithTypes> + pub fn with_types(self) -> NodeBuilderWithTypes> where T: NodeTypes, { - let types = FullNodeTypesAdapter::new(types); - NodeBuilderWithTypes::new(self.config, types, self.database) + NodeBuilderWithTypes::new(self.config, self.database) } /// Preconfigures the node with a specific node implementation. @@ -205,7 +205,7 @@ where where N: Node>, { - self.with_types(node.clone()).with_components(node.components_builder()) + self.with_types().with_components(node.components_builder()) } } @@ -236,15 +236,12 @@ where DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, { /// Configures the types of the node. - pub fn with_types( - self, - types: T, - ) -> WithLaunchContext>> + pub fn with_types(self) -> WithLaunchContext>> where T: NodeTypes, { WithLaunchContext { - builder: self.builder.with_types(types), + builder: self.builder.with_types(), task_executor: self.task_executor, data_dir: self.data_dir, } @@ -260,7 +257,7 @@ where where N: Node>, { - self.with_types(node.clone()).with_components(node.components_builder()) + self.with_types().with_components(node.components_builder()) } /// Launches a preconfigured [Node] @@ -428,8 +425,6 @@ pub struct BuilderContext { pub(crate) config: NodeConfig, /// loaded config pub(crate) reth_config: reth_config::Config, - /// EVM config of the node - pub(crate) evm_config: Node::Evm, } impl BuilderContext { @@ -441,9 +436,8 @@ impl BuilderContext { data_dir: ChainPath, config: NodeConfig, reth_config: reth_config::Config, - evm_config: Node::Evm, ) -> Self { - Self { head, provider, executor, data_dir, config, reth_config, evm_config } + Self { head, provider, executor, data_dir, config, reth_config } } /// Returns the configured provider to interact with the blockchain. @@ -451,11 +445,6 @@ impl BuilderContext { &self.provider } - /// Returns the configured evm. - pub fn evm_config(&self) -> &Node::Evm { - &self.evm_config - } - /// Returns the current head of the blockchain at launch. pub fn head(&self) -> Head { self.head diff --git a/crates/node/builder/src/builder/states.rs b/crates/node/builder/src/builder/states.rs index b77588df4..753978de1 100644 --- a/crates/node/builder/src/builder/states.rs +++ b/crates/node/builder/src/builder/states.rs @@ -31,8 +31,8 @@ pub struct NodeBuilderWithTypes { impl NodeBuilderWithTypes { /// Creates a new instance of the node builder with the given configuration and types. - pub fn new(config: NodeConfig, types: T, database: T::DB) -> Self { - Self { config, adapter: NodeTypesAdapter::new(types, database) } + pub fn new(config: NodeConfig, database: T::DB) -> Self { + Self { config, adapter: NodeTypesAdapter::new(database) } } /// Advances the state of the node builder to the next state where all components are configured @@ -59,14 +59,12 @@ impl NodeBuilderWithTypes { pub(crate) struct NodeTypesAdapter { /// The database type used by the node. pub(crate) database: T::DB, - // TODO(mattsse): make this stateless - pub(crate) types: T, } impl NodeTypesAdapter { /// Create a new adapter from the given node types. - pub(crate) fn new(types: T, database: T::DB) -> Self { - Self { types, database } + pub(crate) fn new(database: T::DB) -> Self { + Self { database } } } @@ -85,18 +83,11 @@ pub struct NodeAdapter> { pub task_executor: TaskExecutor, /// The provider of the node. pub provider: T::Provider, - /// EVM config - pub evm: T::Evm, } impl> NodeTypes for NodeAdapter { type Primitives = T::Primitives; type Engine = T::Engine; - type Evm = T::Evm; - - fn evm_config(&self) -> Self::Evm { - self.evm.clone() - } } impl> FullNodeTypes for NodeAdapter { @@ -106,11 +97,16 @@ impl> FullNodeTypes for NodeAdapter impl> FullNodeComponents for NodeAdapter { type Pool = C::Pool; + type Evm = C::Evm; fn pool(&self) -> &Self::Pool { self.components.pool() } + fn evm_config(&self) -> &Self::Evm { + self.components.evm_config() + } + fn provider(&self) -> &Self::Provider { &self.provider } @@ -134,7 +130,6 @@ impl> Clone for NodeAdapter { components: self.components.clone(), task_executor: self.task_executor.clone(), provider: self.provider.clone(), - evm: self.evm.clone(), } } } diff --git a/crates/node/builder/src/components/builder.rs b/crates/node/builder/src/components/builder.rs index 1c963f024..d17cdc8ee 100644 --- a/crates/node/builder/src/components/builder.rs +++ b/crates/node/builder/src/components/builder.rs @@ -1,13 +1,16 @@ //! A generic [NodeComponentsBuilder] use crate::{ - components::{Components, NetworkBuilder, NodeComponents, PayloadServiceBuilder, PoolBuilder}, - BuilderContext, FullNodeTypes, + components::{ + Components, ExecutorBuilder, NetworkBuilder, NodeComponents, PayloadServiceBuilder, + PoolBuilder, + }, + BuilderContext, ConfigureEvm, FullNodeTypes, }; use reth_transaction_pool::TransactionPool; use std::{future::Future, marker::PhantomData}; -/// A generic, customizable [`NodeComponentsBuilder`]. +/// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation. /// /// This type is stateful and captures the configuration of the node's components. /// @@ -27,21 +30,31 @@ use std::{future::Future, marker::PhantomData}; /// All component builders are captured in the builder state and will be consumed once the node is /// launched. #[derive(Debug)] -pub struct ComponentsBuilder { +pub struct ComponentsBuilder { pool_builder: PoolB, payload_builder: PayloadB, network_builder: NetworkB, + executor_builder: ExecB, _marker: PhantomData, } -impl ComponentsBuilder { +impl + ComponentsBuilder +{ /// Configures the node types. - pub fn node_types(self) -> ComponentsBuilder + pub fn node_types(self) -> ComponentsBuilder where Types: FullNodeTypes, { - let Self { pool_builder, payload_builder, network_builder, _marker } = self; + let Self { + pool_builder, + payload_builder, + network_builder, + executor_builder: evm_builder, + _marker, + } = self; ComponentsBuilder { + executor_builder: evm_builder, pool_builder, payload_builder, network_builder, @@ -55,6 +68,7 @@ impl ComponentsBuilder ComponentsBuilder ComponentsBuilder ExecB) -> Self { + Self { + pool_builder: self.pool_builder, + payload_builder: self.payload_builder, + network_builder: self.network_builder, + executor_builder: f(self.executor_builder), _marker: self._marker, } } } -impl ComponentsBuilder +impl + ComponentsBuilder where Node: FullNodeTypes, { @@ -88,16 +116,32 @@ where /// /// This accepts a [PoolBuilder] instance that will be used to create the node's transaction /// pool. - pub fn pool(self, pool_builder: PB) -> ComponentsBuilder + pub fn pool( + self, + pool_builder: PB, + ) -> ComponentsBuilder where PB: PoolBuilder, { - let Self { pool_builder: _, payload_builder, network_builder, _marker } = self; - ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker } + let Self { + pool_builder: _, + payload_builder, + network_builder, + executor_builder: evm_builder, + _marker, + } = self; + ComponentsBuilder { + pool_builder, + payload_builder, + network_builder, + executor_builder: evm_builder, + _marker, + } } } -impl ComponentsBuilder +impl + ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, @@ -106,57 +150,118 @@ where /// /// This accepts a [NetworkBuilder] instance that will be used to create the node's network /// stack. - pub fn network(self, network_builder: NB) -> ComponentsBuilder + pub fn network( + self, + network_builder: NB, + ) -> ComponentsBuilder where NB: NetworkBuilder, { - let Self { pool_builder, payload_builder, network_builder: _, _marker } = self; - ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker } + let Self { + pool_builder, + payload_builder, + network_builder: _, + executor_builder: evm_builder, + _marker, + } = self; + ComponentsBuilder { + pool_builder, + payload_builder, + network_builder, + executor_builder: evm_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 + pub fn payload( + self, + payload_builder: PB, + ) -> ComponentsBuilder where PB: PayloadServiceBuilder, { - let Self { pool_builder, payload_builder: _, network_builder, _marker } = self; - ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker } + let Self { + pool_builder, + payload_builder: _, + network_builder, + executor_builder: evm_builder, + _marker, + } = self; + ComponentsBuilder { + pool_builder, + payload_builder, + network_builder, + executor_builder: evm_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: _, _marker } = + self; + ComponentsBuilder { + pool_builder, + payload_builder, + network_builder, + executor_builder, + _marker, + } } } -impl NodeComponentsBuilder - for ComponentsBuilder +impl NodeComponentsBuilder + for ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, NetworkB: NetworkBuilder, PayloadB: PayloadServiceBuilder, + ExecB: ExecutorBuilder, { - type Components = Components; + type Components = Components; async fn build_components( self, context: &BuilderContext, ) -> eyre::Result { - let Self { pool_builder, payload_builder, network_builder, _marker } = self; + let Self { + pool_builder, + payload_builder, + network_builder, + executor_builder: evm_builder, + _marker, + } = self; + let evm_config = 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?; - Ok(Components { transaction_pool: pool, network, payload_builder }) + Ok(Components { transaction_pool: pool, evm_config, network, payload_builder }) } } -impl Default for ComponentsBuilder<(), (), (), ()> { +impl Default for ComponentsBuilder<(), (), (), (), ()> { fn default() -> Self { Self { pool_builder: (), payload_builder: (), network_builder: (), + executor_builder: (), _marker: Default::default(), } } @@ -167,9 +272,9 @@ impl Default for ComponentsBuilder<(), (), (), ()> { /// Implementers of this trait are responsible for building all the components of the node: See /// [NodeComponents]. /// -/// The [ComponentsBuilder] is a generic 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. +/// 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 @@ -182,14 +287,15 @@ pub trait NodeComponentsBuilder: Send { ) -> impl Future> + Send; } -impl NodeComponentsBuilder for F +impl NodeComponentsBuilder for F where Node: FullNodeTypes, F: FnOnce(&BuilderContext) -> Fut + Send, - Fut: Future>> + Send, + Fut: Future>> + Send, Pool: TransactionPool + Unpin + 'static, + EVM: ConfigureEvm, { - type Components = Components; + type Components = Components; fn build_components( self, diff --git a/crates/node/builder/src/components/execute.rs b/crates/node/builder/src/components/execute.rs new file mode 100644 index 000000000..417423d54 --- /dev/null +++ b/crates/node/builder/src/components/execute.rs @@ -0,0 +1,34 @@ +//! EVM component for the node builder. +use crate::{BuilderContext, FullNodeTypes}; +use reth_node_api::ConfigureEvm; +use std::future::Future; + +/// A type that knows how to build the executor types. +pub trait ExecutorBuilder: Send { + /// The EVM config to build. + type EVM: ConfigureEvm; + // TODO(mattsse): integrate `Executor` + + /// Creates the transaction pool. + fn build_evm( + self, + ctx: &BuilderContext, + ) -> impl Future> + Send; +} + +impl ExecutorBuilder for F +where + Node: FullNodeTypes, + EVM: ConfigureEvm, + F: FnOnce(&BuilderContext) -> Fut + Send, + Fut: Future> + Send, +{ + type EVM = EVM; + + fn build_evm( + self, + ctx: &BuilderContext, + ) -> impl Future> { + self(ctx) + } +} diff --git a/crates/node/builder/src/components/mod.rs b/crates/node/builder/src/components/mod.rs index ea087ece2..24d83da0d 100644 --- a/crates/node/builder/src/components/mod.rs +++ b/crates/node/builder/src/components/mod.rs @@ -7,8 +7,9 @@ //! //! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes). -use crate::FullNodeTypes; +use crate::{ConfigureEvm, FullNodeTypes}; pub use builder::*; +pub use execute::*; pub use network::*; pub use payload::*; pub use pool::*; @@ -17,11 +18,13 @@ use reth_payload_builder::PayloadBuilderHandle; use reth_transaction_pool::TransactionPool; mod builder; +mod execute; mod network; mod payload; mod pool; /// An abstraction over the components of a node, consisting of: +/// - evm and executor /// - transaction pool /// - network /// - payload builder. @@ -29,9 +32,15 @@ pub trait NodeComponents: Clone + Send + Sync + 'stati /// The transaction pool of the node. type Pool: TransactionPool + Unpin; + /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine. + type Evm: ConfigureEvm; + /// Returns the transaction pool of the node. fn pool(&self) -> &Self::Pool; + /// Returns the node's evm config. + fn evm_config(&self) -> &Self::Evm; + /// Returns the handle to the network fn network(&self) -> &NetworkHandle; @@ -43,26 +52,34 @@ pub trait NodeComponents: Clone + Send + Sync + 'stati /// /// This provides access to all the components of the node. #[derive(Debug)] -pub struct Components { +pub struct Components { /// The transaction pool of the node. pub transaction_pool: Pool, + /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine. + pub evm_config: EVM, /// The network implementation of the node. pub network: NetworkHandle, /// The handle to the payload builder service. pub payload_builder: PayloadBuilderHandle, } -impl NodeComponents for Components +impl NodeComponents for Components where Node: FullNodeTypes, Pool: TransactionPool + Unpin + 'static, + EVM: ConfigureEvm, { type Pool = Pool; + type Evm = EVM; fn pool(&self) -> &Self::Pool { &self.transaction_pool } + fn evm_config(&self) -> &Self::Evm { + &self.evm_config + } + fn network(&self) -> &NetworkHandle { &self.network } @@ -72,14 +89,16 @@ where } } -impl Clone for Components +impl Clone for Components where Node: FullNodeTypes, Pool: TransactionPool, + EVM: ConfigureEvm, { fn clone(&self) -> Self { Self { transaction_pool: self.transaction_pool.clone(), + evm_config: self.evm_config.clone(), network: self.network.clone(), payload_builder: self.payload_builder.clone(), } diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 4f1f00e4e..bd81f8386 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -40,6 +40,7 @@ use tokio::sync::{mpsc::unbounded_channel, oneshot}; pub mod common; pub use common::LaunchContext; +use reth_blockchain_tree::noop::NoopBlockchainTree; /// A general purpose trait that launches a new node of any kind. /// @@ -83,7 +84,7 @@ where ) -> eyre::Result { let Self { ctx } = self; let NodeBuilderWithComponents { - adapter: NodeTypesAdapter { types, database }, + adapter: NodeTypesAdapter { database }, components_builder, add_ons: NodeAddOns { hooks, rpc, exexs: installed_exex }, config, @@ -124,27 +125,22 @@ where let sync_metrics_listener = reth_stages::MetricsListener::new(sync_metrics_rx); ctx.task_executor().spawn_critical("stages metrics listener task", sync_metrics_listener); - // Configure the blockchain tree for the node - let evm_config = types.evm_config(); - let tree_config = BlockchainTreeConfig::default(); - let tree_externals = TreeExternals::new( - ctx.provider_factory().clone(), - consensus.clone(), - EvmProcessorFactory::new(ctx.chain_spec(), evm_config.clone()), - ); - let tree = BlockchainTree::new(tree_externals, tree_config, ctx.prune_modes())? - .with_sync_metrics_tx(sync_metrics_tx.clone()); - - let canon_state_notification_sender = tree.canon_state_notification_sender(); - let blockchain_tree = Arc::new(ShareableBlockchainTree::new(tree)); - debug!(target: "reth::cli", "configured blockchain tree"); - // fetch the head block from the database let head = ctx.lookup_head()?; - // setup the blockchain provider - let blockchain_db = - BlockchainProvider::new(ctx.provider_factory().clone(), blockchain_tree.clone())?; + // Configure the blockchain tree for the node + let tree_config = BlockchainTreeConfig::default(); + + // NOTE: This is a temporary workaround to provide the canon state notification sender to the components builder because there's a cyclic dependency between the blockchain provider and the tree component. This will be removed once the Blockchain provider no longer depends on an instance of the tree: + let (canon_state_notification_sender, _receiver) = + tokio::sync::broadcast::channel(tree_config.max_reorg_depth() as usize * 2); + + let blockchain_db = BlockchainProvider::new( + ctx.provider_factory().clone(), + Arc::new(NoopBlockchainTree::with_canon_state_notifications( + canon_state_notification_sender.clone(), + )), + )?; let builder_ctx = BuilderContext::new( head, @@ -153,19 +149,37 @@ where ctx.data_dir().clone(), ctx.node_config().clone(), ctx.toml_config().clone(), - evm_config.clone(), ); debug!(target: "reth::cli", "creating components"); let components = components_builder.build_components(&builder_ctx).await?; + let tree_externals = TreeExternals::new( + ctx.provider_factory().clone(), + consensus.clone(), + EvmProcessorFactory::new(ctx.chain_spec(), components.evm_config().clone()), + ); + let tree = BlockchainTree::new(tree_externals, tree_config, ctx.prune_modes())? + .with_sync_metrics_tx(sync_metrics_tx.clone()) + // Note: This is required because we need to ensure that both the components and the + // tree are using the same channel for canon state notifications. This will be removed + // once the Blockchain provider no longer depends on an instance of the tree + .with_canon_state_notification_sender(canon_state_notification_sender); + + let canon_state_notification_sender = tree.canon_state_notification_sender(); + let blockchain_tree = Arc::new(ShareableBlockchainTree::new(tree)); + + // Replace the tree component with the actual tree + let blockchain_db = blockchain_db.with_tree(blockchain_tree); + + debug!(target: "reth::cli", "configured blockchain tree"); + let NodeHooks { on_component_initialized, on_node_started, .. } = hooks; let node_adapter = NodeAdapter { components, task_executor: ctx.task_executor().clone(), provider: blockchain_db.clone(), - evm: evm_config.clone(), }; debug!(target: "reth::cli", "calling on_component_initialized hook"); @@ -225,7 +239,7 @@ where }); // send notifications from the blockchain tree to exex manager - let mut canon_state_notifications = blockchain_tree.subscribe_to_canonical_state(); + let mut canon_state_notifications = blockchain_db.subscribe_to_canonical_state(); let mut handle = exex_manager_handle.clone(); ctx.task_executor().spawn_critical( "exex manager blockchain tree notifications", @@ -305,7 +319,7 @@ address.to_string(), format_ether(alloc.balance)); consensus_engine_tx.clone(), canon_state_notification_sender, mining_mode, - evm_config.clone(), + node_adapter.components.evm_config().clone(), ) .build(); @@ -320,7 +334,7 @@ address.to_string(), format_ether(alloc.balance)); ctx.prune_config(), max_block, static_file_producer, - evm_config, + node_adapter.components.evm_config().clone(), pipeline_exex_handle, ) .await?; @@ -343,7 +357,7 @@ address.to_string(), format_ether(alloc.balance)); ctx.prune_config(), max_block, static_file_producer, - evm_config, + node_adapter.components.evm_config().clone(), pipeline_exex_handle, ) .await?; @@ -447,7 +461,7 @@ address.to_string(), format_ether(alloc.balance)); }); let full_node = FullNode { - evm_config: node_adapter.evm.clone(), + evm_config: node_adapter.components.evm_config().clone(), pool: node_adapter.components.pool().clone(), network: node_adapter.components.network().clone(), provider: node_adapter.provider.clone(), diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index a65dcfce5..3ac553fa3 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -274,7 +274,7 @@ where .with_network(node.network().clone()) .with_events(node.provider().clone()) .with_executor(node.task_executor().clone()) - .with_evm_config(node.evm_config()) + .with_evm_config(node.evm_config().clone()) .build_with_auth_server(module_config, engine_api); let mut registry = RpcRegistry { registry }; diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index 8f6a3c19b..a7b195f48 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -6,10 +6,13 @@ use crate::{ OptimismEngineTypes, }; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; +use reth_evm::ConfigureEvm; use reth_evm_optimism::OptimismEvmConfig; use reth_network::{NetworkHandle, NetworkManager}; use reth_node_builder::{ - components::{ComponentsBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder}, + components::{ + ComponentsBuilder, ExecutorBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder, + }, node::{FullNodeTypes, NodeTypes}, BuilderContext, Node, PayloadBuilderConfig, }; @@ -38,7 +41,13 @@ impl OptimismNode { /// Returns the components for the given [RollupArgs]. pub fn components( args: RollupArgs, - ) -> ComponentsBuilder + ) -> ComponentsBuilder< + Node, + OptimismPoolBuilder, + OptimismPayloadBuilder, + OptimismNetworkBuilder, + OptimismExecutorBuilder, + > where Node: FullNodeTypes, { @@ -46,8 +55,12 @@ impl OptimismNode { ComponentsBuilder::default() .node_types::() .pool(OptimismPoolBuilder::default()) - .payload(OptimismPayloadBuilder::new(compute_pending_block)) + .payload(OptimismPayloadBuilder::new( + compute_pending_block, + OptimismEvmConfig::default(), + )) .network(OptimismNetworkBuilder { disable_txpool_gossip }) + .executor(OptimismExecutorBuilder::default()) } } @@ -55,8 +68,13 @@ impl Node for OptimismNode where N: FullNodeTypes, { - type ComponentsBuilder = - ComponentsBuilder; + type ComponentsBuilder = ComponentsBuilder< + N, + OptimismPoolBuilder, + OptimismPayloadBuilder, + OptimismNetworkBuilder, + OptimismExecutorBuilder, + >; fn components_builder(self) -> Self::ComponentsBuilder { let Self { args } = self; @@ -67,10 +85,21 @@ where impl NodeTypes for OptimismNode { type Primitives = (); type Engine = OptimismEngineTypes; - type Evm = OptimismEvmConfig; +} - fn evm_config(&self) -> Self::Evm { - OptimismEvmConfig::default() +/// A regular optimism evm and executor builder. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct OptimismExecutorBuilder; + +impl ExecutorBuilder for OptimismExecutorBuilder +where + Node: FullNodeTypes, +{ + type EVM = OptimismEvmConfig; + + async fn build_evm(self, _ctx: &BuilderContext) -> eyre::Result { + Ok(OptimismEvmConfig::default()) } } @@ -151,7 +180,7 @@ where /// A basic optimism payload service builder #[derive(Debug, Default, Clone)] -pub struct OptimismPayloadBuilder { +pub struct OptimismPayloadBuilder { /// By default the pending block equals the latest block /// to save resources and not leak txs from the tx-pool, /// this flag enables computing of the pending block @@ -161,19 +190,22 @@ pub struct OptimismPayloadBuilder { /// will use the payload attributes from the latest block. Note /// that this flag is not yet functional. pub compute_pending_block: bool, + /// The EVM configuration to use for the payload builder. + pub evm_config: EVM, } -impl OptimismPayloadBuilder { - /// Create a new instance with the given `compute_pending_block` flag. - pub const fn new(compute_pending_block: bool) -> Self { - Self { compute_pending_block } +impl OptimismPayloadBuilder { + /// Create a new instance with the given `compute_pending_block` flag and evm config. + pub const fn new(compute_pending_block: bool, evm_config: EVM) -> Self { + Self { compute_pending_block, evm_config } } } -impl PayloadServiceBuilder for OptimismPayloadBuilder +impl PayloadServiceBuilder for OptimismPayloadBuilder where Node: FullNodeTypes, Pool: TransactionPool + Unpin + 'static, + EVM: ConfigureEvm, { async fn spawn_payload_service( self, @@ -182,7 +214,7 @@ where ) -> eyre::Result> { let payload_builder = reth_optimism_payload_builder::OptimismPayloadBuilder::new( ctx.chain_spec(), - ctx.evm_config().clone(), + self.evm_config, ) .set_compute_pending_block(self.compute_pending_block); let conf = ctx.payload_builder_config(); diff --git a/crates/optimism/node/tests/it/builder.rs b/crates/optimism/node/tests/it/builder.rs index 64f96bd2d..5d26e8bda 100644 --- a/crates/optimism/node/tests/it/builder.rs +++ b/crates/optimism/node/tests/it/builder.rs @@ -12,7 +12,7 @@ fn test_basic_setup() { let db = create_test_rw_db(); let _builder = NodeBuilder::new(config) .with_database(db) - .with_types(OptimismNode::default()) + .with_types::() .with_components(OptimismNode::components(Default::default())) .on_component_initialized(move |ctx| { let _provider = ctx.provider(); diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index f58f77dd0..b0f43ba9f 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -89,6 +89,13 @@ impl BlockchainProvider { ) -> Self { Self { database, tree, chain_info: ChainInfoTracker::new(latest) } } + + /// Sets the treeviewer for the provider. + #[doc(hidden)] + pub fn with_tree(mut self, tree: Arc) -> Self { + self.tree = tree; + self + } } impl BlockchainProvider diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index 79639e1ba..ada28c0f3 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -37,9 +37,8 @@ use reth_node_api::{ EngineTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, }; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{ - node::{EthereumNetworkBuilder, EthereumPoolBuilder}, - EthEvmConfig, +use reth_node_ethereum::node::{ + EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder, }; use reth_payload_builder::{ error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, @@ -187,12 +186,6 @@ impl NodeTypes for MyCustomNode { type Primitives = (); // use the custom engine types type Engine = CustomEngineTypes; - // use the default ethereum EVM config - type Evm = EthEvmConfig; - - fn evm_config(&self) -> Self::Evm { - Self::Evm::default() - } } /// Implement the Node trait for the custom node @@ -207,6 +200,7 @@ where EthereumPoolBuilder, CustomPayloadServiceBuilder, EthereumNetworkBuilder, + EthereumExecutorBuilder, >; fn components_builder(self) -> Self::ComponentsBuilder { @@ -215,6 +209,7 @@ where .pool(EthereumPoolBuilder::default()) .payload(CustomPayloadServiceBuilder::default()) .network(EthereumNetworkBuilder::default()) + .executor(EthereumExecutorBuilder::default()) } } diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index 6c80c9a74..e5362c808 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -3,7 +3,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] use reth::{ - builder::{node::NodeTypes, NodeBuilder}, + builder::{components::ExecutorBuilder, BuilderContext, NodeBuilder}, primitives::{ address, revm_primitives::{CfgEnvWithHandlerCfg, Env, PrecompileResult, TxEnv}, @@ -17,9 +17,9 @@ use reth::{ }, tasks::TaskManager, }; -use reth_node_api::{ConfigureEvm, ConfigureEvmEnv}; +use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{EthEngineTypes, EthEvmConfig, EthereumNode}; +use reth_node_ethereum::{EthEvmConfig, EthereumNode}; use reth_primitives::{Chain, ChainSpec, Genesis, Header, Transaction}; use reth_tracing::{RethTracer, Tracer}; use std::sync::Arc; @@ -104,18 +104,19 @@ impl ConfigureEvm for MyEvmConfig { } } -#[derive(Debug, Clone, Default)] +/// A regular ethereum evm and executor builder. +#[derive(Debug, Default, Clone, Copy)] #[non_exhaustive] -struct MyCustomNode; +pub struct MyExecutorBuilder; -/// Configure the node types -impl NodeTypes for MyCustomNode { - type Primitives = (); - type Engine = EthEngineTypes; - type Evm = MyEvmConfig; +impl ExecutorBuilder for MyExecutorBuilder +where + Node: FullNodeTypes, +{ + type EVM = MyEvmConfig; - fn evm_config(&self) -> Self::Evm { - Self::Evm::default() + async fn build_evm(self, _ctx: &BuilderContext) -> eyre::Result { + Ok(MyEvmConfig::default()) } } @@ -140,8 +141,8 @@ async fn main() -> eyre::Result<()> { let handle = NodeBuilder::new(node_config) .testing_node(tasks.executor()) - .with_types(MyCustomNode::default()) - .with_components(EthereumNode::components()) + .with_types::() + .with_components(EthereumNode::components().executor(MyExecutorBuilder::default())) .launch() .await .unwrap(); diff --git a/examples/custom-node-components/src/main.rs b/examples/custom-node-components/src/main.rs index 96672807d..a6db90674 100644 --- a/examples/custom-node-components/src/main.rs +++ b/examples/custom-node-components/src/main.rs @@ -19,7 +19,7 @@ fn main() { .run(|builder, _| async move { let handle = builder // use the default ethereum node types - .with_types(EthereumNode::default()) + .with_types::() // Configure the components of the node // use default ethereum components but use our custom pool .with_components(EthereumNode::components().pool(CustomPoolBuilder::default())) diff --git a/examples/custom-payload-builder/src/main.rs b/examples/custom-payload-builder/src/main.rs index 8e028771b..2c468c34a 100644 --- a/examples/custom-payload-builder/src/main.rs +++ b/examples/custom-payload-builder/src/main.rs @@ -73,7 +73,7 @@ fn main() { Cli::parse_args() .run(|builder, _| async move { let handle = builder - .with_types(EthereumNode::default()) + .with_types::() // Configure the components of the node // use default ethereum components but use our custom payload builder .with_components(