diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index ebcbaed12..eb3e2b3bf 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -344,7 +344,7 @@ impl OpEthApiBuilder { blocking_task_pool, ctx.new_fee_history_cache(), ctx.evm_config.clone(), - ctx.executor.clone(), + Box::new(ctx.executor.clone()), ctx.config.proof_permits, ); diff --git a/crates/rpc/rpc/src/eth/builder.rs b/crates/rpc/rpc/src/eth/builder.rs new file mode 100644 index 000000000..844686451 --- /dev/null +++ b/crates/rpc/rpc/src/eth/builder.rs @@ -0,0 +1,189 @@ +//! `EthApiBuilder` implementation + +use crate::{ + eth::{core::EthApiInner, EthTxBuilder}, + EthApi, +}; +use reth_provider::{BlockReaderIdExt, StateProviderFactory}; +use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle}; +use reth_rpc_server_types::constants::{ + DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_PROOF_PERMITS, +}; +use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor}; +use std::sync::Arc; + +/// A helper to build the `EthApi` handler instance. +/// +/// This builder type contains all settings to create an [`EthApiInner`] or an [`EthApi`] instance +/// directly. +#[derive(Debug)] +pub struct EthApiBuilder +where + Provider: BlockReaderIdExt, +{ + provider: Provider, + pool: Pool, + network: Network, + evm_config: EvmConfig, + gas_cap: GasCap, + max_simulate_blocks: u64, + eth_proof_window: u64, + fee_history_cache: FeeHistoryCache, + proof_permits: usize, + eth_cache: Option>, + gas_oracle: Option>, + blocking_task_pool: Option, + task_spawner: Box, +} + +impl EthApiBuilder +where + Provider: BlockReaderIdExt, +{ + /// Creates a new `EthApiBuilder` instance. + pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self + where + Provider: BlockReaderIdExt, + { + Self { + provider, + pool, + network, + evm_config, + eth_cache: None, + gas_oracle: None, + gas_cap: GasCap::default(), + max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS, + eth_proof_window: DEFAULT_ETH_PROOF_WINDOW, + blocking_task_pool: None, + fee_history_cache: FeeHistoryCache::new(Default::default()), + proof_permits: DEFAULT_PROOF_PERMITS, + task_spawner: TokioTaskExecutor::default().boxed(), + } + } + + /// Configures the task spawner used to spawn additional tasks. + pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self { + self.task_spawner = Box::new(spawner); + self + } + + /// Sets `eth_cache` instance + pub fn eth_cache( + mut self, + eth_cache: EthStateCache, + ) -> Self { + self.eth_cache = Some(eth_cache); + self + } + + /// Sets `gas_oracle` instance + pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle) -> Self { + self.gas_oracle = Some(gas_oracle); + self + } + + /// Sets the gas cap. + pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self { + self.gas_cap = gas_cap; + self + } + + /// Sets the maximum number of blocks for `eth_simulateV1`. + pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self { + self.max_simulate_blocks = max_simulate_blocks; + self + } + + /// Sets the maximum number of blocks into the past for generating state proofs. + pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self { + self.eth_proof_window = eth_proof_window; + self + } + + /// Sets the blocking task pool. + pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self { + self.blocking_task_pool = Some(blocking_task_pool); + self + } + + /// Sets the fee history cache. + pub fn fee_history_cache(mut self, fee_history_cache: FeeHistoryCache) -> Self { + self.fee_history_cache = fee_history_cache; + self + } + + /// Sets the proof permits. + pub const fn proof_permits(mut self, proof_permits: usize) -> Self { + self.proof_permits = proof_permits; + self + } + + /// Builds the [`EthApiInner`] instance. + /// + /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`]. + /// + /// # Panics + /// + /// This function panics if the blocking task pool cannot be built. + /// This will panic if called outside the context of a Tokio runtime. + pub fn build_inner(self) -> EthApiInner + where + Provider: BlockReaderIdExt + StateProviderFactory + Clone + Unpin + 'static, + { + let Self { + provider, + pool, + network, + evm_config, + eth_cache, + gas_oracle, + gas_cap, + max_simulate_blocks, + eth_proof_window, + blocking_task_pool, + fee_history_cache, + proof_permits, + task_spawner, + } = self; + + let eth_cache = + eth_cache.unwrap_or_else(|| EthStateCache::spawn(provider.clone(), Default::default())); + let gas_oracle = gas_oracle.unwrap_or_else(|| { + GasPriceOracle::new(provider.clone(), Default::default(), eth_cache.clone()) + }); + + EthApiInner::new( + provider, + pool, + network, + eth_cache, + gas_oracle, + gas_cap, + max_simulate_blocks, + eth_proof_window, + blocking_task_pool.unwrap_or_else(|| { + BlockingTaskPool::build().expect("failed to build blocking task pool") + }), + fee_history_cache, + evm_config, + task_spawner, + proof_permits, + ) + } + + /// Builds the [`EthApi`] instance. + /// + /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`]. + /// + /// # Panics + /// + /// This function panics if the blocking task pool cannot be built. + /// This will panic if called outside the context of a Tokio runtime. + pub fn build(self) -> EthApi + where + Provider: BlockReaderIdExt + StateProviderFactory + Clone + Unpin + 'static, + { + EthApi { inner: Arc::new(self.build_inner()), tx_resp_builder: EthTxBuilder } + } +} diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 58c06a2df..63978871e 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -3,6 +3,7 @@ use std::sync::Arc; +use crate::{eth::EthTxBuilder, EthApiBuilder}; use alloy_consensus::BlockHeader; use alloy_eips::BlockNumberOrTag; use alloy_network::Ethereum; @@ -28,8 +29,6 @@ use reth_tasks::{ }; use tokio::sync::{broadcast, Mutex}; -use crate::eth::EthTxBuilder; - const DEFAULT_BROADCAST_CAPACITY: usize = 2000; /// `Eth` API implementation. @@ -63,6 +62,16 @@ impl EthApi EthApiBuilder { + EthApiBuilder::new(provider, pool, network, evm_config) + } + /// Creates a new, shareable instance using the default tokio task spawner. #[allow(clippy::too_many_arguments)] pub fn new( @@ -91,7 +100,7 @@ where blocking_task_pool, fee_history_cache, evm_config, - TokioTaskExecutor::default(), + TokioTaskExecutor::default().boxed(), proof_permits, ); @@ -133,7 +142,7 @@ where blocking_task_pool, ctx.new_fee_history_cache(), ctx.evm_config.clone(), - ctx.executor.clone(), + Box::new(ctx.executor.clone()), ctx.config.proof_permits, ); @@ -294,7 +303,7 @@ where blocking_task_pool: BlockingTaskPool, fee_history_cache: FeeHistoryCache, evm_config: EvmConfig, - task_spawner: impl TaskSpawner + 'static, + task_spawner: Box, proof_permits: usize, ) -> Self { let signers = parking_lot::RwLock::new(Default::default()); @@ -321,7 +330,7 @@ where max_simulate_blocks, eth_proof_window, starting_block, - task_spawner: Box::new(task_spawner), + task_spawner, pending_block: Default::default(), blocking_task_pool, fee_history_cache, @@ -451,7 +460,7 @@ where #[cfg(test)] mod tests { - use crate::EthApi; + use crate::{EthApi, EthApiBuilder}; use alloy_consensus::Header; use alloy_eips::BlockNumberOrTag; use alloy_primitives::{PrimitiveSignature as Signature, B256, U64}; @@ -466,13 +475,6 @@ mod tests { BlockReader, BlockReaderIdExt, ChainSpecProvider, StateProviderFactory, }; use reth_rpc_eth_api::EthApiServer; - use reth_rpc_eth_types::{ - EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasCap, GasPriceOracle, - }; - use reth_rpc_server_types::constants::{ - DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_PROOF_PERMITS, - }; - use reth_tasks::pool::BlockingTaskPool; use reth_testing_utils::{generators, generators::Rng}; use reth_transaction_pool::test_utils::{testing_pool, TestPool}; @@ -490,24 +492,13 @@ mod tests { >( provider: P, ) -> EthApi { - let evm_config = EthEvmConfig::new(provider.chain_spec()); - let cache = EthStateCache::spawn(provider.clone(), Default::default()); - let fee_history_cache = FeeHistoryCache::new(FeeHistoryCacheConfig::default()); - - EthApi::new( + EthApiBuilder::new( provider.clone(), testing_pool(), NoopNetwork::default(), - cache.clone(), - GasPriceOracle::new(provider, Default::default(), cache), - GasCap::default(), - DEFAULT_MAX_SIMULATE_BLOCKS, - DEFAULT_ETH_PROOF_WINDOW, - BlockingTaskPool::build().expect("failed to build tracing pool"), - fee_history_cache, - evm_config, - DEFAULT_PROOF_PERMITS, + EthEvmConfig::new(provider.chain_spec()), ) + .build() } // Function to prepare the EthApi with mock data diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs index d8a5b95f5..4530efba4 100644 --- a/crates/rpc/rpc/src/eth/mod.rs +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -1,5 +1,6 @@ //! Sever implementation of `eth` namespace API. +pub mod builder; pub mod bundle; pub mod core; pub mod filter; @@ -8,6 +9,7 @@ pub mod pubsub; pub mod sim_bundle; /// Implementation of `eth` namespace API. +pub use builder::EthApiBuilder; pub use bundle::EthBundle; pub use core::EthApi; pub use filter::EthFilter; diff --git a/crates/rpc/rpc/src/lib.rs b/crates/rpc/rpc/src/lib.rs index d957913df..bac57b630 100644 --- a/crates/rpc/rpc/src/lib.rs +++ b/crates/rpc/rpc/src/lib.rs @@ -49,7 +49,7 @@ mod web3; pub use admin::AdminApi; pub use debug::DebugApi; pub use engine::{EngineApi, EngineEthApi}; -pub use eth::{EthApi, EthBundle, EthFilter, EthPubSub}; +pub use eth::{EthApi, EthApiBuilder, EthBundle, EthFilter, EthPubSub}; pub use miner::MinerApi; pub use net::NetApi; pub use otterscan::OtterscanApi; diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index 340e925ec..505d433c8 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -113,7 +113,7 @@ pub struct TokioTaskExecutor; impl TokioTaskExecutor { /// Converts the instance to a boxed [`TaskSpawner`]. - pub fn boxed(self) -> Box { + pub fn boxed(self) -> Box { Box::new(self) } }