feat(rpc): created EthApiBuilder type (#14041)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Dhruv Agarwal
2025-01-29 19:13:10 +05:30
committed by GitHub
parent 5fcefcea8c
commit 6d5514964b
6 changed files with 213 additions and 31 deletions

View File

@ -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<Provider, Pool, Network, EvmConfig>
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<EthStateCache<Provider::Block, Provider::Receipt>>,
gas_oracle: Option<GasPriceOracle<Provider>>,
blocking_task_pool: Option<BlockingTaskPool>,
task_spawner: Box<dyn TaskSpawner + 'static>,
}
impl<Provider, Pool, Network, EvmConfig> EthApiBuilder<Provider, Pool, Network, EvmConfig>
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<Provider::Block, Provider::Receipt>,
) -> Self {
self.eth_cache = Some(eth_cache);
self
}
/// Sets `gas_oracle` instance
pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<Provider>) -> 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<Provider, Pool, Network, EvmConfig>
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<Provider, Pool, Network, EvmConfig>
where
Provider: BlockReaderIdExt + StateProviderFactory + Clone + Unpin + 'static,
{
EthApi { inner: Arc::new(self.build_inner()), tx_resp_builder: EthTxBuilder }
}
}

View File

@ -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<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConf
where
Provider: BlockReaderIdExt,
{
/// Convenience fn to obtain a new [`EthApiBuilder`] instance with mandatory components
pub fn builder(
provider: Provider,
pool: Pool,
network: Network,
evm_config: EvmConfig,
) -> EthApiBuilder<Provider, Pool, Network, EvmConfig> {
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<dyn TaskSpawner + 'static>,
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<P, TestPool, NoopNetwork, EthEvmConfig> {
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

View File

@ -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;

View File

@ -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;