diff --git a/Cargo.lock b/Cargo.lock index ee2c03566..bdae392a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8151,6 +8151,7 @@ dependencies = [ "alloy-rlp", "assert_matches", "async-trait", + "derive_more", "futures", "http 1.1.0", "http-body", @@ -8252,6 +8253,7 @@ dependencies = [ "reth-rpc", "reth-rpc-api", "reth-rpc-engine-api", + "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-layer", "reth-rpc-server-types", diff --git a/crates/ethereum/node/tests/e2e/dev.rs b/crates/ethereum/node/tests/e2e/dev.rs index 2b20d781f..0e289cfd3 100644 --- a/crates/ethereum/node/tests/e2e/dev.rs +++ b/crates/ethereum/node/tests/e2e/dev.rs @@ -19,7 +19,7 @@ async fn can_run_dev_node() -> eyre::Result<()> { Ok(()) } -async fn assert_chain_advances(mut node: EthNode) { +async fn assert_chain_advances(node: EthNode) { let mut notifications = node.inner.provider.canonical_state_stream(); // submit tx through rpc diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 99dc04310..2efde0c5a 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -308,7 +308,7 @@ where let jwt_secret = ctx.auth_jwt_secret()?; // Start RPC servers - let (rpc_server_handles, mut rpc_registry) = crate::rpc::launch_rpc_servers( + let (rpc_server_handles, rpc_registry) = crate::rpc::launch_rpc_servers( ctx.node_adapter().clone(), engine_api, ctx.node_config(), diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index 9a7a86b91..7f6cb5e89 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -1,22 +1,24 @@ //! Builder support for rpc components. +use std::{ + fmt, + ops::{Deref, DerefMut}, +}; + use futures::TryFutureExt; use reth_network::NetworkHandle; use reth_node_api::FullNodeComponents; use reth_node_core::{node_config::NodeConfig, rpc::api::EngineApiServer}; use reth_payload_builder::PayloadBuilderHandle; +use reth_rpc::eth::EthApi; use reth_rpc_builder::{ auth::{AuthRpcModule, AuthServerHandle}, config::RethRpcServerConfig, - RethModuleRegistry, RpcModuleBuilder, RpcServerHandle, TransportRpcModules, + EthApiBuild, RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, }; use reth_rpc_layer::JwtSecret; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; -use std::{ - fmt, - ops::{Deref, DerefMut}, -}; /// Contains the handles to the spawned RPC servers. /// @@ -145,27 +147,28 @@ impl ExtendRpcModules for () { } } -/// Helper wrapper type to encapsulate the [`RethModuleRegistry`] over components trait. +/// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait. #[derive(Debug)] +#[allow(clippy::type_complexity)] pub struct RpcRegistry { - pub(crate) registry: RethModuleRegistry< + pub(crate) registry: RpcRegistryInner< Node::Provider, Node::Pool, NetworkHandle, TaskExecutor, Node::Provider, - Node::Evm, + EthApi, >, } impl Deref for RpcRegistry { - type Target = RethModuleRegistry< + type Target = RpcRegistryInner< Node::Provider, Node::Pool, NetworkHandle, TaskExecutor, Node::Provider, - Node::Evm, + EthApi, >; fn deref(&self) -> &Self::Target { @@ -185,7 +188,7 @@ impl Clone for RpcRegistry { } } -/// Helper container to encapsulate [`RethModuleRegistry`], [`TransportRpcModules`] and +/// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and /// [`AuthRpcModule`]. /// /// This can be used to access installed modules, or create commonly used handlers like @@ -202,7 +205,7 @@ pub struct RpcContext<'a, Node: FullNodeComponents> { /// A Helper type the holds instances of the configured modules. /// - /// This provides easy access to rpc handlers, such as [`RethModuleRegistry::eth_api`]. + /// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`]. pub registry: &'a mut RpcRegistry, /// Holds installed modules per transport type. /// @@ -272,7 +275,7 @@ where .with_events(node.provider().clone()) .with_executor(node.task_executor().clone()) .with_evm_config(node.evm_config().clone()) - .build_with_auth_server(module_config, engine_api); + .build_with_auth_server(module_config, engine_api, EthApiBuild::build); let mut registry = RpcRegistry { registry }; let ctx = RpcContext { diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 7b7c89c0f..d97b23b51 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -19,6 +19,7 @@ reth-node-core.workspace = true reth-provider.workspace = true reth-rpc.workspace = true reth-rpc-api.workspace = true +reth-rpc-eth-api.workspace = true reth-rpc-layer.workspace = true reth-rpc-eth-types.workspace = true reth-rpc-server-types.workspace = true diff --git a/crates/rpc/rpc-builder/src/auth.rs b/crates/rpc/rpc-builder/src/auth.rs index 952362e0c..be904f6ef 100644 --- a/crates/rpc/rpc-builder/src/auth.rs +++ b/crates/rpc/rpc-builder/src/auth.rs @@ -1,5 +1,3 @@ -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - use crate::error::{RpcError, ServerKind}; use http::header::AUTHORIZATION; use jsonrpsee::{ @@ -9,13 +7,14 @@ use jsonrpsee::{ Methods, }; use reth_engine_primitives::EngineTypes; -use reth_rpc_api::*; +use reth_rpc_api::servers::*; use reth_rpc_eth_types::EthSubscriptionIdProvider; use reth_rpc_layer::{ secret_to_bearer_header, AuthClientLayer, AuthClientService, AuthLayer, JwtAuthValidator, JwtSecret, }; use reth_rpc_server_types::constants; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use tower::layer::util::Identity; pub use jsonrpsee::server::ServerBuilder; diff --git a/crates/rpc/rpc-builder/src/config.rs b/crates/rpc/rpc-builder/src/config.rs index fbace8ec7..e2becedba 100644 --- a/crates/rpc/rpc-builder/src/config.rs +++ b/crates/rpc/rpc-builder/src/config.rs @@ -214,13 +214,11 @@ impl RethRpcServerConfig for RpcServerArgs { #[cfg(test)] mod tests { - use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; - use clap::{Args, Parser}; use reth_node_core::args::RpcServerArgs; - use reth_rpc_server_types::{ - constants, constants::gas_oracle::RPC_DEFAULT_GAS_CAP, RethRpcModule, RpcModuleSelection, - }; + use reth_rpc_eth_types::RPC_DEFAULT_GAS_CAP; + use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection}; + use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use crate::config::RethRpcServerConfig; diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 7d177ed43..43e20b1ea 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -1,232 +1,136 @@ -use std::sync::Arc; +use std::{fmt::Debug, time::Duration}; use reth_evm::ConfigureEvm; -use reth_network_api::{NetworkInfo, Peers}; +use reth_network_api::NetworkInfo; use reth_provider::{ - AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - EvmEnvProvider, StateProviderFactory, + BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider, + FullRpcProvider, StateProviderFactory, }; -use reth_rpc::eth::{EthApi, EthFilter, EthFilterConfig, EthPubSub, RawTransactionForwarder}; +use reth_rpc::{eth::EthFilterConfig, EthApi, EthFilter, EthPubSub}; use reth_rpc_eth_types::{ cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache, EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, - GasPriceOracleConfig, + GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP, }; use reth_rpc_server_types::constants::{ - default_max_tracing_requests, gas_oracle::RPC_DEFAULT_GAS_CAP, DEFAULT_MAX_BLOCKS_PER_FILTER, - DEFAULT_MAX_LOGS_PER_RESPONSE, + default_max_tracing_requests, DEFAULT_MAX_BLOCKS_PER_FILTER, DEFAULT_MAX_LOGS_PER_RESPONSE, }; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; use reth_transaction_pool::TransactionPool; use serde::{Deserialize, Serialize}; -use crate::RpcModuleConfig; +/// Default value for stale filter ttl +const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60); -/// All handlers for the `eth` namespace +/// Alias for function that builds the core `eth` namespace API. +pub type EthApiBuilder = + Box) -> EthApi>; + +/// Handlers for core, filter and pubsub `eth` namespace APIs. #[derive(Debug, Clone)] -pub struct EthHandlers { +pub struct EthHandlers { /// Main `eth_` request handler - pub api: EthApi, + pub api: EthApi, /// The async caching layer used by the eth handlers pub cache: EthStateCache, /// Polling based filter handler available on all transports pub filter: EthFilter, /// Handler for subscriptions only available for transports that support it (ws, ipc) pub pubsub: EthPubSub, - /// The configured tracing call pool - pub blocking_task_pool: BlockingTaskPool, } -/// Configuration for `EthHandlersBuilder` -#[derive(Clone, Debug)] -pub(crate) struct EthHandlersConfig { - /// The provider for blockchain data, responsible for reading blocks, accounts, state, etc. - pub(crate) provider: Provider, - /// The transaction pool for managing pending transactions. - pub(crate) pool: Pool, - /// The network information, handling peer connections and network state. - pub(crate) network: Network, - /// The task executor for spawning asynchronous tasks. - pub(crate) executor: Tasks, - /// The event subscriptions for canonical state changes. - pub(crate) events: Events, - /// The EVM configuration for Ethereum Virtual Machine settings. - pub(crate) evm_config: EvmConfig, - /// An optional forwarder for raw transactions. - pub(crate) eth_raw_transaction_forwarder: Option>, +impl EthHandlers { + /// Returns a new [`EthHandlers`] builder. + #[allow(clippy::too_many_arguments)] + pub fn builder( + provider: Provider, + pool: Pool, + network: Network, + evm_config: EvmConfig, + config: EthConfig, + executor: Tasks, + events: Events, + eth_api_builder: EthApiB, + ) -> EthHandlersBuilder + where + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + { + EthHandlersBuilder { + provider, + pool, + network, + evm_config, + config, + executor, + events, + eth_api_builder: Box::new(eth_api_builder), + } + } } -/// Represents the builder for the `EthHandlers` struct, used to configure and create instances of -/// `EthHandlers`. -#[derive(Debug, Clone)] -pub(crate) struct EthHandlersBuilder { - eth_handlers_config: EthHandlersConfig, - /// Configuration for the RPC module - rpc_config: RpcModuleConfig, +/// Builds [`EthHandlers`] for core, filter, and pubsub `eth_` apis. +#[allow(missing_debug_implementations)] +pub struct EthHandlersBuilder { + provider: Provider, + pool: Pool, + network: Network, + evm_config: EvmConfig, + config: EthConfig, + executor: Tasks, + events: Events, + eth_api_builder: EthApiBuilder, } -impl - EthHandlersBuilder +impl + EthHandlersBuilder where - Provider: BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, - Network: NetworkInfo + Peers + Clone + 'static, + Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, + Pool: Send + Sync + Clone + 'static, + EvmConfig: ConfigureEvm, + Network: Clone, Tasks: TaskSpawner + Clone + 'static, - Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm + 'static, + Events: CanonStateSubscriptions + Clone, { - /// Creates a new `EthHandlersBuilder` with the provided components. - pub(crate) const fn new( - eth_handlers_config: EthHandlersConfig, - rpc_config: RpcModuleConfig, - ) -> Self { - Self { eth_handlers_config, rpc_config } - } + /// Returns a new instance with handlers for `eth` namespace. + pub fn build(self) -> EthHandlers { + let Self { provider, pool, network, evm_config, config, executor, events, eth_api_builder } = + self; - /// Builds and returns an `EthHandlers` instance. - pub(crate) fn build(self) -> EthHandlers { - // Initialize the cache - let cache = self.init_cache(); + let cache = EthStateCache::spawn_with( + provider.clone(), + config.cache, + executor.clone(), + evm_config.clone(), + ); - // Initialize the fee history cache - let fee_history_cache = self.init_fee_history_cache(&cache); - - // Spawn background tasks for cache - self.spawn_cache_tasks(&cache, &fee_history_cache); - - // Initialize the gas oracle - let gas_oracle = self.init_gas_oracle(&cache); - - // Initialize the blocking task pool - let blocking_task_pool = self.init_blocking_task_pool(); - - // Initialize the Eth API - let api = self.init_api(&cache, gas_oracle, &fee_history_cache, &blocking_task_pool); - - // Initialize the filter - let filter = self.init_filter(&cache); - - // Initialize the pubsub - let pubsub = self.init_pubsub(); - - EthHandlers { api, cache, filter, pubsub, blocking_task_pool } - } - - /// Initializes the `EthStateCache`. - fn init_cache(&self) -> EthStateCache { - EthStateCache::spawn_with( - self.eth_handlers_config.provider.clone(), - self.rpc_config.eth.cache.clone(), - self.eth_handlers_config.executor.clone(), - self.eth_handlers_config.evm_config.clone(), - ) - } - - /// Initializes the `FeeHistoryCache`. - fn init_fee_history_cache(&self, cache: &EthStateCache) -> FeeHistoryCache { - FeeHistoryCache::new(cache.clone(), self.rpc_config.eth.fee_history_cache.clone()) - } - - /// Spawns background tasks for updating caches. - fn spawn_cache_tasks(&self, cache: &EthStateCache, fee_history_cache: &FeeHistoryCache) { - // Get the stream of new canonical blocks - let new_canonical_blocks = self.eth_handlers_config.events.canonical_state_stream(); - - // Clone the cache for the task - let cache_clone = cache.clone(); - - // Spawn a critical task to update the cache with new blocks - self.eth_handlers_config.executor.spawn_critical( + let new_canonical_blocks = events.canonical_state_stream(); + let c = cache.clone(); + executor.spawn_critical( "cache canonical blocks task", Box::pin(async move { - cache_new_blocks_task(cache_clone, new_canonical_blocks).await; + cache_new_blocks_task(c, new_canonical_blocks).await; }), ); - // Get another stream of new canonical blocks - let new_canonical_blocks = self.eth_handlers_config.events.canonical_state_stream(); + let ctx = EthApiBuilderCtx { + provider, + pool, + network, + evm_config, + config, + executor, + events, + cache, + }; - // Clone the fee history cache for the task - let fhc_clone = fee_history_cache.clone(); + let api = eth_api_builder(&ctx); - // Clone the provider for the task - let provider_clone = self.eth_handlers_config.provider.clone(); + let filter = EthFilterApiBuilder::build(&ctx); - // Spawn a critical task to update the fee history cache with new blocks - self.eth_handlers_config.executor.spawn_critical( - "cache canonical blocks for fee history task", - Box::pin(async move { - fee_history_cache_new_blocks_task(fhc_clone, new_canonical_blocks, provider_clone) - .await; - }), - ); - } + let pubsub = EthPubSubApiBuilder::build(&ctx); - /// Initializes the `GasPriceOracle`. - fn init_gas_oracle(&self, cache: &EthStateCache) -> GasPriceOracle { - GasPriceOracle::new( - self.eth_handlers_config.provider.clone(), - self.rpc_config.eth.gas_oracle.clone(), - cache.clone(), - ) - } - - /// Initializes the `BlockingTaskPool`. - fn init_blocking_task_pool(&self) -> BlockingTaskPool { - BlockingTaskPool::build().expect("failed to build tracing pool") - } - - /// Initializes the `EthApi`. - fn init_api( - &self, - cache: &EthStateCache, - gas_oracle: GasPriceOracle, - fee_history_cache: &FeeHistoryCache, - blocking_task_pool: &BlockingTaskPool, - ) -> EthApi { - EthApi::with_spawner( - self.eth_handlers_config.provider.clone(), - self.eth_handlers_config.pool.clone(), - self.eth_handlers_config.network.clone(), - cache.clone(), - gas_oracle, - self.rpc_config.eth.rpc_gas_cap, - Box::new(self.eth_handlers_config.executor.clone()), - blocking_task_pool.clone(), - fee_history_cache.clone(), - self.eth_handlers_config.evm_config.clone(), - self.eth_handlers_config.eth_raw_transaction_forwarder.clone(), - ) - } - - /// Initializes the `EthFilter`. - fn init_filter(&self, cache: &EthStateCache) -> EthFilter { - EthFilter::new( - self.eth_handlers_config.provider.clone(), - self.eth_handlers_config.pool.clone(), - cache.clone(), - self.rpc_config.eth.filter_config(), - Box::new(self.eth_handlers_config.executor.clone()), - ) - } - - /// Initializes the `EthPubSub`. - fn init_pubsub(&self) -> EthPubSub { - EthPubSub::with_spawner( - self.eth_handlers_config.provider.clone(), - self.eth_handlers_config.pool.clone(), - self.eth_handlers_config.events.clone(), - self.eth_handlers_config.network.clone(), - Box::new(self.eth_handlers_config.executor.clone()), - ) + EthHandlers { api, cache: ctx.cache, filter, pubsub } } } @@ -249,7 +153,7 @@ pub struct EthConfig { pub rpc_gas_cap: u64, /// /// Sets TTL for stale filters - pub stale_filter_ttl: std::time::Duration, + pub stale_filter_ttl: Duration, /// Settings for the fee history cache pub fee_history_cache: FeeHistoryCacheConfig, } @@ -264,9 +168,6 @@ impl EthConfig { } } -/// Default value for stale filter ttl -const DEFAULT_STALE_FILTER_TTL: std::time::Duration = std::time::Duration::from_secs(5 * 60); - impl Default for EthConfig { fn default() -> Self { Self { @@ -275,7 +176,7 @@ impl Default for EthConfig { max_tracing_requests: default_max_tracing_requests(), max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER, max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE, - rpc_gas_cap: RPC_DEFAULT_GAS_CAP, + rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(), stale_filter_ttl: DEFAULT_STALE_FILTER_TTL, fee_history_cache: FeeHistoryCacheConfig::default(), } @@ -319,3 +220,157 @@ impl EthConfig { self } } + +/// Context for building the `eth` namespace API. +#[derive(Debug, Clone)] +pub struct EthApiBuilderCtx { + /// Database handle. + pub provider: Provider, + /// Mempool handle. + pub pool: Pool, + /// Network handle. + pub network: Network, + /// EVM configuration. + pub evm_config: EvmConfig, + /// RPC config for `eth` namespace. + pub config: EthConfig, + /// Runtime handle. + pub executor: Tasks, + /// Events handle. + pub events: Events, + /// RPC cache handle. + pub cache: EthStateCache, +} + +/// Ethereum layer one `eth` RPC server builder. +#[derive(Default, Debug, Clone, Copy)] +pub struct EthApiBuild; + +impl EthApiBuild { + /// Builds the [`EthApiServer`](reth_rpc_eth_api::EthApiServer), for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> EthApi + where + Provider: FullRpcProvider, + Pool: TransactionPool, + Network: NetworkInfo + Clone, + Tasks: TaskSpawner + Clone + 'static, + Events: CanonStateSubscriptions, + EvmConfig: ConfigureEvm, + { + let gas_oracle = GasPriceOracleBuilder::build(ctx); + let fee_history_cache = FeeHistoryCacheBuilder::build(ctx); + + EthApi::with_spawner( + ctx.provider.clone(), + ctx.pool.clone(), + ctx.network.clone(), + ctx.cache.clone(), + gas_oracle, + ctx.config.rpc_gas_cap, + Box::new(ctx.executor.clone()), + BlockingTaskPool::build().expect("failed to build blocking task pool"), + fee_history_cache, + ctx.evm_config.clone(), + None, + ) + } +} + +/// Builds the `eth_` namespace API [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer). +#[derive(Debug)] +pub struct EthFilterApiBuilder; + +impl EthFilterApiBuilder { + /// Builds the [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer), for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> EthFilter + where + Provider: Send + Sync + Clone + 'static, + Pool: Send + Sync + Clone + 'static, + Tasks: TaskSpawner + Clone + 'static, + { + EthFilter::new( + ctx.provider.clone(), + ctx.pool.clone(), + ctx.cache.clone(), + ctx.config.filter_config(), + Box::new(ctx.executor.clone()), + ) + } +} + +/// Builds the `eth_` namespace API [`EthPubSubApiServer`](reth_rpc_eth_api::EthFilterApiServer). +#[derive(Debug)] +pub struct EthPubSubApiBuilder; + +impl EthPubSubApiBuilder { + /// Builds the [`EthPubSubApiServer`](reth_rpc_eth_api::EthPubSubApiServer), for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> EthPubSub + where + Provider: Clone, + Pool: Clone, + Events: Clone, + Network: Clone, + Tasks: TaskSpawner + Clone + 'static, + { + EthPubSub::with_spawner( + ctx.provider.clone(), + ctx.pool.clone(), + ctx.events.clone(), + ctx.network.clone(), + Box::new(ctx.executor.clone()), + ) + } +} + +/// Builds `eth_` core api component [`GasPriceOracle`], for given context. +#[derive(Debug)] +pub struct GasPriceOracleBuilder; + +impl GasPriceOracleBuilder { + /// Builds a [`GasPriceOracle`], for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> GasPriceOracle + where + Provider: BlockReaderIdExt + Clone, + { + GasPriceOracle::new(ctx.provider.clone(), ctx.config.gas_oracle, ctx.cache.clone()) + } +} + +/// Builds `eth_` core api component [`FeeHistoryCache`], for given context. +#[derive(Debug)] +pub struct FeeHistoryCacheBuilder; + +impl FeeHistoryCacheBuilder { + /// Builds a [`FeeHistoryCache`], for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> FeeHistoryCache + where + Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, + Tasks: TaskSpawner, + Events: CanonStateSubscriptions, + { + let fee_history_cache = + FeeHistoryCache::new(ctx.cache.clone(), ctx.config.fee_history_cache); + + let new_canonical_blocks = ctx.events.canonical_state_stream(); + let fhc = fee_history_cache.clone(); + let provider = ctx.provider.clone(); + ctx.executor.spawn_critical( + "cache canonical blocks for fee history task", + Box::pin(async move { + fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider).await; + }), + ); + + fee_history_cache + } +} diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 2800e83d1..7e5faf8bb 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -19,13 +19,12 @@ //! ``` //! use reth_evm::ConfigureEvm; //! use reth_network_api::{NetworkInfo, Peers}; -//! use reth_provider::{ -//! AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, -//! ChangeSetReader, EvmEnvProvider, StateProviderFactory, -//! }; +//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; //! use reth_rpc_builder::{ -//! RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig, +//! EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, +//! TransportRpcModuleConfig, //! }; +//! //! use reth_tasks::TokioTaskExecutor; //! use reth_transaction_pool::TransactionPool; //! pub async fn launch( @@ -35,16 +34,8 @@ //! events: Events, //! evm_config: EvmConfig, //! ) where -//! Provider: AccountReader -//! + BlockReaderIdExt -//! + ChainSpecProvider -//! + ChangeSetReader -//! + StateProviderFactory -//! + EvmEnvProvider -//! + Clone -//! + Unpin -//! + 'static, -//! Pool: TransactionPool + Clone + 'static, +//! Provider: FullRpcProvider + AccountReader + ChangeSetReader, +//! Pool: TransactionPool + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, //! EvmConfig: ConfigureEvm, @@ -64,7 +55,7 @@ //! events, //! evm_config, //! ) -//! .build(transports); +//! .build(transports, EthApiBuild::build); //! let handle = RpcServerConfig::default() //! .with_http(ServerBuilder::default()) //! .start(transport_modules) @@ -80,13 +71,10 @@ //! use reth_engine_primitives::EngineTypes; //! use reth_evm::ConfigureEvm; //! use reth_network_api::{NetworkInfo, Peers}; -//! use reth_provider::{ -//! AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, -//! ChangeSetReader, EvmEnvProvider, StateProviderFactory, -//! }; +//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; //! use reth_rpc_api::EngineApiServer; //! use reth_rpc_builder::{ -//! auth::AuthServerConfig, RethRpcModule, RpcModuleBuilder, RpcServerConfig, +//! auth::AuthServerConfig, EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, //! TransportRpcModuleConfig, //! }; //! use reth_rpc_layer::JwtSecret; @@ -101,16 +89,8 @@ //! engine_api: EngineApi, //! evm_config: EvmConfig, //! ) where -//! Provider: AccountReader -//! + BlockReaderIdExt -//! + ChainSpecProvider -//! + ChangeSetReader -//! + StateProviderFactory -//! + EvmEnvProvider -//! + Clone -//! + Unpin -//! + 'static, -//! Pool: TransactionPool + Clone + 'static, +//! Provider: FullRpcProvider + AccountReader + ChangeSetReader, +//! Pool: TransactionPool + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, //! EngineApi: EngineApiServer, @@ -135,7 +115,7 @@ //! //! // configure the server modules //! let (modules, auth_module, _registry) = -//! builder.build_with_auth_server(transports, engine_api); +//! builder.build_with_auth_server(transports, engine_api, EthApiBuild::build); //! //! // start the servers //! let auth_config = AuthServerConfig::builder(JwtSecret::random()).build(); @@ -155,13 +135,14 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use crate::{ - auth::AuthRpcModule, - cors::CorsDomainError, - error::WsHttpSamePortError, - eth::{EthHandlersBuilder, EthHandlersConfig}, - metrics::RpcRequestMetrics, +use std::{ + collections::HashMap, + fmt, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + sync::Arc, + time::{Duration, SystemTime, UNIX_EPOCH}, }; + use error::{ConflictingModules, RpcError, ServerKind}; use http::{header::AUTHORIZATION, HeaderMap}; use jsonrpsee::{ @@ -174,30 +155,33 @@ use reth_evm::ConfigureEvm; use reth_ipc::server::IpcServer; use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers}; use reth_provider::{ - AccountReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, - ChangeSetReader, EvmEnvProvider, StateProviderFactory, + AccountReader, BlockReader, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, + EvmEnvProvider, FullRpcProvider, StateProviderFactory, }; use reth_rpc::{ - eth::{EthApi, EthBundle, RawTransactionForwarder}, - AdminApi, DebugApi, EngineEthApi, NetApi, OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi, - Web3Api, + AdminApi, DebugApi, EngineEthApi, EthBundle, NetApi, OtterscanApi, RPCApi, RethApi, TraceApi, + TxPoolApi, Web3Api, +}; +use reth_rpc_api::servers::*; +use reth_rpc_eth_api::{ + helpers::{ + Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt, UpdateRawTxForwarder, + }, + EthApiServer, FullEthApiServer, RawTransactionForwarder, }; -use reth_rpc_api::*; use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret}; use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - fmt, - net::{Ipv4Addr, SocketAddr, SocketAddrV4}, - sync::Arc, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; use tower_http::cors::CorsLayer; use tracing::{instrument, trace}; +use crate::{ + auth::AuthRpcModule, cors::CorsDomainError, error::WsHttpSamePortError, + metrics::RpcRequestMetrics, +}; + // re-export for convenience pub use jsonrpsee::server::ServerBuilder; pub use reth_ipc::server::{ @@ -219,15 +203,18 @@ mod cors; pub mod error; /// Eth utils -mod eth; -pub use eth::{EthConfig, EthHandlers}; +pub mod eth; +pub use eth::{ + EthApiBuild, EthApiBuilderCtx, EthConfig, EthHandlers, FeeHistoryCacheBuilder, + GasPriceOracleBuilder, +}; // Rpc server metrics mod metrics; /// Convenience function for starting a server in one step. #[allow(clippy::too_many_arguments)] -pub async fn launch( +pub async fn launch( provider: Provider, pool: Pool, network: Network, @@ -236,27 +223,23 @@ pub async fn launch( executor: Tasks, events: Events, evm_config: EvmConfig, + eth: EthApiB, ) -> Result where - Provider: BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, + Provider: FullRpcProvider + AccountReader + ChangeSetReader, + Pool: TransactionPool + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, EvmConfig: ConfigureEvm, + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + EthApi: FullEthApiServer, { let module_config = module_config.into(); let server_config = server_config.into(); RpcModuleBuilder::new(provider, pool, network, executor, events, evm_config) - .build(module_config) + .build(module_config, eth) .start_server(server_config) .await } @@ -324,8 +307,8 @@ impl /// Configure a [`NoopTransactionPool`] instance. /// /// Caution: This will configure a pool API that does absolutely nothing. - /// This is only intended for allow easier setup of namespaces that depend on the [`EthApi`] - /// which requires a [`TransactionPool`] implementation. + /// This is only intended for allow easier setup of namespaces that depend on the + /// [`EthApi`](reth_rpc::eth::EthApi) which requires a [`TransactionPool`] implementation. pub fn with_noop_pool( self, ) -> RpcModuleBuilder { @@ -355,8 +338,8 @@ impl /// Configure a [`NoopNetwork`] instance. /// /// Caution: This will configure a network API that does absolutely nothing. - /// This is only intended for allow easier setup of namespaces that depend on the [`EthApi`] - /// which requires a [`NetworkInfo`] implementation. + /// This is only intended for allow easier setup of namespaces that depend on the + /// [`EthApi`](reth_rpc::eth::EthApi) which requires a [`NetworkInfo`] implementation. pub fn with_noop_network( self, ) -> RpcModuleBuilder { @@ -429,16 +412,8 @@ impl impl RpcModuleBuilder where - Provider: BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, + Provider: FullRpcProvider + AccountReader + ChangeSetReader, + Pool: TransactionPool + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, @@ -450,25 +425,31 @@ where /// This behaves exactly as [`RpcModuleBuilder::build`] for the [`TransportRpcModules`], but /// also configures the auth (engine api) server, which exposes a subset of the `eth_` /// namespace. - pub fn build_with_auth_server( + #[allow(clippy::type_complexity)] + pub fn build_with_auth_server( self, module_config: TransportRpcModuleConfig, engine: EngineApi, + eth: EthApiB, ) -> ( TransportRpcModules, AuthRpcModule, - RethModuleRegistry, + RpcRegistryInner, ) where EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + EthApi: FullEthApiServer, { let Self { provider, pool, network, executor, events, evm_config } = self; let config = module_config.config.clone().unwrap_or_default(); - let mut registry = - RethModuleRegistry::new(provider, pool, network, executor, events, config, evm_config); + let mut registry = RpcRegistryInner::new( + provider, pool, network, executor, events, config, evm_config, eth, + ); let modules = registry.create_transport_rpc_modules(module_config); @@ -477,7 +458,7 @@ where (modules, auth_module, registry) } - /// Converts the builder into a [`RethModuleRegistry`] which can be used to create all + /// Converts the builder into a [`RpcRegistryInner`] which can be used to create all /// components. /// /// This is useful for getting access to API handlers directly: @@ -488,7 +469,7 @@ where /// use reth_evm::ConfigureEvm; /// use reth_network_api::noop::NoopNetwork; /// use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; - /// use reth_rpc_builder::RpcModuleBuilder; + /// use reth_rpc_builder::{EthApiBuild, RpcModuleBuilder}; /// use reth_tasks::TokioTaskExecutor; /// use reth_transaction_pool::noop::NoopTransactionPool; /// @@ -500,24 +481,38 @@ where /// .with_executor(TokioTaskExecutor::default()) /// .with_events(TestCanonStateSubscriptions::default()) /// .with_evm_config(evm) - /// .into_registry(Default::default()); + /// .into_registry(Default::default(), EthApiBuild::build); /// /// let eth_api = registry.eth_api(); /// } /// ``` - pub fn into_registry( + pub fn into_registry( self, config: RpcModuleConfig, - ) -> RethModuleRegistry { + eth: EthApiB, + ) -> RpcRegistryInner + where + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + { let Self { provider, pool, network, executor, events, evm_config } = self; - RethModuleRegistry::new(provider, pool, network, executor, events, config, evm_config) + RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth) } /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can /// be used to start the transport server(s). /// /// See also [`RpcServer::start`] - pub fn build(self, module_config: TransportRpcModuleConfig) -> TransportRpcModules<()> { + pub fn build( + self, + module_config: TransportRpcModuleConfig, + eth: EthApiB, + ) -> TransportRpcModules<()> + where + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + EthApi: FullEthApiServer, + { let mut modules = TransportRpcModules::default(); let Self { provider, pool, network, executor, events, evm_config } = self; @@ -525,7 +520,7 @@ where if !module_config.is_empty() { let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone(); - let mut registry = RethModuleRegistry::new( + let mut registry = RpcRegistryInner::new( provider, pool, network, @@ -533,6 +528,7 @@ where events, config.unwrap_or_default(), evm_config, + eth, ); modules.config = module_config; @@ -621,34 +617,34 @@ impl RpcModuleConfigBuilder { /// A Helper type the holds instances of the configured modules. #[derive(Debug, Clone)] -pub struct RethModuleRegistry { +pub struct RpcRegistryInner { provider: Provider, pool: Pool, network: Network, executor: Tasks, events: Events, - /// Defines how to configure the EVM before execution. - evm_config: EvmConfig, - /// Additional settings for handlers. - config: RpcModuleConfig, - /// Holds a clone of all the eth namespace handlers - eth: Option>, + /// Holds a all `eth_` namespace handlers + eth: EthHandlers, /// to put trace calls behind semaphore blocking_pool_guard: BlockingTaskGuard, /// Contains the [Methods] of a module modules: HashMap, - /// Optional forwarder for `eth_sendRawTransaction` - // TODO(mattsse): find a more ergonomic way to configure eth/rpc customizations - eth_raw_transaction_forwarder: Option>, } -// === impl RethModuleRegistry === +// === impl RpcRegistryInner === -impl - RethModuleRegistry +impl + RpcRegistryInner +where + Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, + Pool: Send + Sync + Clone + 'static, + Network: Clone, + Events: CanonStateSubscriptions + Clone, + Tasks: TaskSpawner + Clone + 'static, { /// Creates a new, empty instance. - pub fn new( + #[allow(clippy::too_many_arguments)] + pub fn new( provider: Provider, pool: Pool, network: Network, @@ -656,34 +652,59 @@ impl events: Events, config: RpcModuleConfig, evm_config: EvmConfig, - ) -> Self { + eth_api_builder: EthApiB, + ) -> Self + where + EvmConfig: ConfigureEvm, + EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi + + 'static, + { + let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests); + + let eth = EthHandlers::builder( + provider.clone(), + pool.clone(), + network.clone(), + evm_config, + config.eth, + executor.clone(), + events.clone(), + eth_api_builder, + ) + .build(); + Self { provider, pool, network, - evm_config, - eth: None, + eth, executor, modules: Default::default(), - blocking_pool_guard: BlockingTaskGuard::new(config.eth.max_tracing_requests), - config, + blocking_pool_guard, events, - eth_raw_transaction_forwarder: None, } } +} - /// Sets a forwarder for `eth_sendRawTransaction` +impl + RpcRegistryInner +{ + /// Returns a reference to the installed [`EthApi`](reth_rpc::eth::EthApi). + pub const fn eth_api(&self) -> &EthApi { + &self.eth.api + } + + /// Returns a reference to the installed [`EthHandlers`]. + pub const fn eth_handlers(&self) -> &EthHandlers { + &self.eth + } + + /// Returns the [`EthStateCache`] frontend /// - /// Note: this might be removed in the future in favor of a more generic approach. - pub fn set_eth_raw_transaction_forwarder( - &mut self, - forwarder: Arc, - ) { - if let Some(eth) = self.eth.as_ref() { - // in case the eth api has been created before the forwarder was set: - eth.api.set_eth_raw_transaction_forwarder(forwarder.clone()); - } - self.eth_raw_transaction_forwarder = Some(forwarder); + /// This will spawn exactly one [`EthStateCache`] service if this is the first time the cache is + /// requested. + pub const fn eth_cache(&self) -> &EthStateCache { + &self.eth.cache } /// Returns a reference to the pool @@ -721,13 +742,30 @@ impl } } -impl - RethModuleRegistry +impl + RpcRegistryInner where - Network: NetworkInfo + Peers + Clone + 'static, + EthApi: UpdateRawTxForwarder, +{ + /// Sets a forwarder for `eth_sendRawTransaction` + /// + /// Note: this might be removed in the future in favor of a more generic approach. + pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { + // in case the eth api has been created before the forwarder was set: + self.eth.api.set_eth_raw_transaction_forwarder(forwarder.clone()); + } +} + +impl + RpcRegistryInner +where + Network: NetworkInfo + Clone + 'static, { /// Instantiates `AdminApi` - pub fn admin_api(&self) -> AdminApi { + pub fn admin_api(&self) -> AdminApi + where + Network: Peers, + { AdminApi::new(self.network.clone(), self.provider.chain_spec()) } @@ -737,7 +775,10 @@ where } /// Register Admin Namespace - pub fn register_admin(&mut self) -> &mut Self { + pub fn register_admin(&mut self) -> &mut Self + where + Network: Peers, + { let adminapi = self.admin_api(); self.modules.insert(RethRpcModule::Admin, adminapi.into_rpc().into()); self @@ -751,31 +792,24 @@ where } } -impl - RethModuleRegistry +impl + RpcRegistryInner where - Provider: BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, + Provider: FullRpcProvider + AccountReader + ChangeSetReader, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, - Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm, + EthApi: Clone, { /// Register Eth Namespace /// /// # Panics /// /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn register_eth(&mut self) -> &mut Self { - let eth_api = self.eth_api(); + pub fn register_eth(&mut self) -> &mut Self + where + EthApi: EthApiServer, + { + let eth_api = self.eth_api().clone(); self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into()); self } @@ -785,7 +819,10 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn register_ots(&mut self) -> &mut Self { + pub fn register_ots(&mut self) -> &mut Self + where + EthApi: EthApiServer + TraceExt, + { let otterscan_api = self.otterscan_api(); self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into()); self @@ -796,7 +833,10 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn register_debug(&mut self) -> &mut Self { + pub fn register_debug(&mut self) -> &mut Self + where + EthApi: EthApiSpec + EthTransactions + TraceExt, + { let debug_api = self.debug_api(); self.modules.insert(RethRpcModule::Debug, debug_api.into_rpc().into()); self @@ -807,34 +847,15 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn register_trace(&mut self) -> &mut Self { + pub fn register_trace(&mut self) -> &mut Self + where + EthApi: TraceExt, + { let trace_api = self.trace_api(); self.modules.insert(RethRpcModule::Trace, trace_api.into_rpc().into()); self } - /// Configures the auth module that includes the - /// * `engine_` namespace - /// * `api_` namespace - /// - /// Note: This does _not_ register the `engine_` in this registry. - pub fn create_auth_module(&mut self, engine_api: EngineApi) -> AuthRpcModule - where - EngineT: EngineTypes + 'static, - EngineApi: EngineApiServer, - { - let eth_handlers = self.eth_handlers(); - let mut module = RpcModule::new(()); - - module.merge(engine_api.into_rpc()).expect("No conflicting methods"); - - // also merge a subset of `eth_` handlers - let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter); - module.merge(engine_eth.into_rpc()).expect("No conflicting methods"); - - AuthRpcModule { inner: module } - } - /// Register Net Namespace /// /// See also [`Self::eth_api`] @@ -842,7 +863,10 @@ where /// # Panics /// /// If called outside of the tokio runtime. - pub fn register_net(&mut self) -> &mut Self { + pub fn register_net(&mut self) -> &mut Self + where + EthApi: EthApiSpec + 'static, + { let netapi = self.net_api(); self.modules.insert(RethRpcModule::Net, netapi.into_rpc().into()); self @@ -861,6 +885,113 @@ where self } + /// Instantiates `TraceApi` + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn trace_api(&self) -> TraceApi + where + EthApi: TraceExt, + { + TraceApi::new( + self.provider.clone(), + self.eth_api().clone(), + self.blocking_pool_guard.clone(), + ) + } + + /// Instantiates [`EthBundle`] Api + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn bundle_api(&self) -> EthBundle + where + EthApi: EthTransactions + LoadPendingBlock + Call, + { + let eth_api = self.eth_api().clone(); + EthBundle::new(eth_api, self.blocking_pool_guard.clone()) + } + + /// Instantiates `OtterscanApi` + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn otterscan_api(&self) -> OtterscanApi + where + EthApi: EthApiServer, + { + let eth_api = self.eth_api().clone(); + OtterscanApi::new(eth_api) + } + + /// Instantiates `DebugApi` + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn debug_api(&self) -> DebugApi + where + EthApi: EthApiSpec + EthTransactions + TraceExt, + { + let eth_api = self.eth_api().clone(); + DebugApi::new(self.provider.clone(), eth_api, self.blocking_pool_guard.clone()) + } + + /// Instantiates `NetApi` + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn net_api(&self) -> NetApi + where + EthApi: EthApiSpec + 'static, + { + let eth_api = self.eth_api().clone(); + NetApi::new(self.network.clone(), eth_api) + } + + /// Instantiates `RethApi` + pub fn reth_api(&self) -> RethApi { + RethApi::new(self.provider.clone(), Box::new(self.executor.clone())) + } +} + +impl + RpcRegistryInner +where + Provider: FullRpcProvider + AccountReader + ChangeSetReader, + Pool: TransactionPool + 'static, + Network: NetworkInfo + Peers + Clone + 'static, + Tasks: TaskSpawner + Clone + 'static, + Events: CanonStateSubscriptions + Clone + 'static, + EthApi: FullEthApiServer, +{ + /// Configures the auth module that includes the + /// * `engine_` namespace + /// * `api_` namespace + /// + /// Note: This does _not_ register the `engine_` in this registry. + pub fn create_auth_module(&self, engine_api: EngineApi) -> AuthRpcModule + where + EngineT: EngineTypes + 'static, + EngineApi: EngineApiServer, + { + let mut module = RpcModule::new(()); + + module.merge(engine_api.into_rpc()).expect("No conflicting methods"); + + // also merge a subset of `eth_` handlers + let eth_handlers = self.eth_handlers(); + let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone()); + + module.merge(engine_eth.into_rpc()).expect("No conflicting methods"); + + AuthRpcModule { inner: module } + } + /// Helper function to create a [`RpcModule`] if it's not `None` fn maybe_module(&mut self, config: Option<&RpcModuleSelection>) -> Option> { config.map(|config| self.module_for(config)) @@ -908,13 +1039,8 @@ where &mut self, namespaces: impl Iterator, ) -> Vec { - let EthHandlers { - api: eth_api, - filter: eth_filter, - pubsub: eth_pubsub, - cache: _, - blocking_task_pool: _, - } = self.with_eth(|eth| eth.clone()); + let EthHandlers { api: eth_api, filter: eth_filter, pubsub: eth_pubsub, .. } = + self.eth_handlers().clone(); // Create a copy, so we can list out all the methods for rpc_ api let namespaces: Vec<_> = namespaces.collect(); @@ -983,120 +1109,6 @@ where }) .collect::>() } - - /// Returns the [`EthStateCache`] frontend - /// - /// This will spawn exactly one [`EthStateCache`] service if this is the first time the cache is - /// requested. - pub fn eth_cache(&mut self) -> EthStateCache { - self.with_eth(|handlers| handlers.cache.clone()) - } - - /// Creates the [`EthHandlers`] type the first time this is called. - /// - /// This will spawn the required service tasks for [`EthApi`] for: - /// - [`EthStateCache`] - /// - [`FeeHistoryCache`](reth_rpc_eth_types::FeeHistoryCache) - fn with_eth(&mut self, f: F) -> R - where - F: FnOnce(&EthHandlers) -> R, - { - f(match &self.eth { - Some(eth) => eth, - None => self.eth.insert(self.init_eth()), - }) - } - - fn init_eth(&self) -> EthHandlers { - EthHandlersBuilder::new( - EthHandlersConfig { - provider: self.provider.clone(), - pool: self.pool.clone(), - network: self.network.clone(), - executor: self.executor.clone(), - events: self.events.clone(), - evm_config: self.evm_config.clone(), - eth_raw_transaction_forwarder: self.eth_raw_transaction_forwarder.clone(), - }, - self.config.clone(), - ) - .build() - } - - /// Returns the configured [`EthHandlers`] or creates it if it does not exist yet - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn eth_handlers(&mut self) -> EthHandlers { - self.with_eth(|handlers| handlers.clone()) - } - - /// Returns the configured [`EthApi`] or creates it if it does not exist yet - /// - /// Caution: This will spawn the necessary tasks required by the [`EthApi`]: [`EthStateCache`]. - /// - /// # Panics - /// - /// If called outside of the tokio runtime. - pub fn eth_api(&mut self) -> EthApi { - self.with_eth(|handlers| handlers.api.clone()) - } - - /// Instantiates `TraceApi` - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn trace_api(&mut self) -> TraceApi> { - let eth = self.eth_handlers(); - TraceApi::new(self.provider.clone(), eth.api, self.blocking_pool_guard.clone()) - } - - /// Instantiates [`EthBundle`] Api - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn bundle_api(&mut self) -> EthBundle> { - let eth_api = self.eth_api(); - EthBundle::new(eth_api, self.blocking_pool_guard.clone()) - } - - /// Instantiates `OtterscanApi` - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn otterscan_api(&mut self) -> OtterscanApi> { - let eth_api = self.eth_api(); - OtterscanApi::new(eth_api) - } - - /// Instantiates `DebugApi` - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn debug_api(&mut self) -> DebugApi> { - let eth_api = self.eth_api(); - DebugApi::new(self.provider.clone(), eth_api, self.blocking_pool_guard.clone()) - } - - /// Instantiates `NetApi` - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn net_api(&mut self) -> NetApi> { - let eth_api = self.eth_api(); - NetApi::new(self.network.clone(), eth_api) - } - - /// Instantiates `RethApi` - pub fn reth_api(&self) -> RethApi { - RethApi::new(self.provider.clone(), Box::new(self.executor.clone())) - } } /// A builder type for configuring and launching the servers that will handle RPC requests. diff --git a/crates/rpc/rpc-builder/tests/it/startup.rs b/crates/rpc/rpc-builder/tests/it/startup.rs index 91800166f..4c873f2b3 100644 --- a/crates/rpc/rpc-builder/tests/it/startup.rs +++ b/crates/rpc/rpc-builder/tests/it/startup.rs @@ -1,14 +1,16 @@ //! Startup tests +use std::io; + +use reth_rpc_builder::{ + error::{RpcError, ServerKind, WsHttpSamePortError}, + EthApiBuild, RpcServerConfig, TransportRpcModuleConfig, +}; +use reth_rpc_server_types::RethRpcModule; + use crate::utils::{ launch_http, launch_http_ws_same_port, launch_ws, test_address, test_rpc_builder, }; -use reth_rpc_builder::{ - error::{RpcError, ServerKind, WsHttpSamePortError}, - RpcServerConfig, TransportRpcModuleConfig, -}; -use reth_rpc_server_types::RethRpcModule; -use std::io; fn is_addr_in_use_kind(err: &RpcError, kind: ServerKind) -> bool { match err { @@ -24,7 +26,8 @@ async fn test_http_addr_in_use() { let handle = launch_http(vec![RethRpcModule::Admin]).await; let addr = handle.http_local_addr().unwrap(); let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin])); + let server = builder + .build(TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]), EthApiBuild::build); let result = server .start_server(RpcServerConfig::http(Default::default()).with_http_address(addr)) .await; @@ -37,7 +40,8 @@ async fn test_ws_addr_in_use() { let handle = launch_ws(vec![RethRpcModule::Admin]).await; let addr = handle.ws_local_addr().unwrap(); let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin])); + let server = builder + .build(TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]), EthApiBuild::build); let result = server.start_server(RpcServerConfig::ws(Default::default()).with_ws_address(addr)).await; let err = result.unwrap_err(); @@ -58,6 +62,7 @@ async fn test_launch_same_port_different_modules() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]) .with_http(vec![RethRpcModule::Eth]), + EthApiBuild::build, ); let addr = test_address(); let res = server @@ -81,6 +86,7 @@ async fn test_launch_same_port_same_cors() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) .with_http(vec![RethRpcModule::Eth]), + EthApiBuild::build, ); let addr = test_address(); let res = server @@ -102,6 +108,7 @@ async fn test_launch_same_port_different_cors() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) .with_http(vec![RethRpcModule::Eth]), + EthApiBuild::build, ); let addr = test_address(); let res = server diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index d751b2d33..85c9dbeac 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -1,3 +1,5 @@ +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use reth_beacon_consensus::BeaconConsensusEngineHandle; use reth_chainspec::MAINNET; use reth_ethereum_engine_primitives::EthEngineTypes; @@ -7,7 +9,7 @@ use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; use reth_rpc_builder::{ auth::{AuthRpcModule, AuthServerConfig, AuthServerHandle}, - RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig, + EthApiBuild, RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig, }; use reth_rpc_engine_api::EngineApi; use reth_rpc_layer::JwtSecret; @@ -15,7 +17,6 @@ use reth_rpc_server_types::RpcModuleSelection; use reth_rpc_types::engine::{ClientCode, ClientVersionV1}; use reth_tasks::TokioTaskExecutor; use reth_transaction_pool::test_utils::{TestPool, TestPoolBuilder}; -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use tokio::sync::mpsc::unbounded_channel; /// Localhost with port 0 so a free port is used. @@ -51,7 +52,7 @@ pub async fn launch_auth(secret: JwtSecret) -> AuthServerHandle { /// Launches a new server with http only with the given modules pub async fn launch_http(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_http(modules)); + let server = builder.build(TransportRpcModuleConfig::set_http(modules), EthApiBuild::build); server .start_server(RpcServerConfig::http(Default::default()).with_http_address(test_address())) .await @@ -61,7 +62,7 @@ pub async fn launch_http(modules: impl Into) -> RpcServerHan /// Launches a new server with ws only with the given modules pub async fn launch_ws(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_ws(modules)); + let server = builder.build(TransportRpcModuleConfig::set_ws(modules), EthApiBuild::build); server .start_server(RpcServerConfig::ws(Default::default()).with_ws_address(test_address())) .await @@ -72,8 +73,10 @@ pub async fn launch_ws(modules: impl Into) -> RpcServerHandl pub async fn launch_http_ws(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); let modules = modules.into(); - let server = - builder.build(TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules)); + let server = builder.build( + TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), + EthApiBuild::build, + ); server .start_server( RpcServerConfig::ws(Default::default()) @@ -89,8 +92,10 @@ pub async fn launch_http_ws(modules: impl Into) -> RpcServer pub async fn launch_http_ws_same_port(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); let modules = modules.into(); - let server = - builder.build(TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules)); + let server = builder.build( + TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), + EthApiBuild::build, + ); let addr = test_address(); server .start_server( diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 834682670..1f5ced83d 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -16,9 +16,16 @@ use reth_rpc_types::{ use tracing::trace; use crate::helpers::{ - EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace, + transaction::UpdateRawTxForwarder, EthApiSpec, EthBlocks, EthCall, EthFees, EthState, + EthTransactions, FullEthApi, }; +/// Helper trait, unifies functionality that must be supported to implement all RPC methods for +/// server. +pub trait FullEthApiServer: EthApiServer + FullEthApi + UpdateRawTxForwarder + Clone {} + +impl FullEthApiServer for T where T: EthApiServer + FullEthApi + UpdateRawTxForwarder + Clone {} + /// Eth rpc interface: #[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))] @@ -324,14 +331,7 @@ pub trait EthApi { #[async_trait::async_trait] impl EthApiServer for T where - Self: EthApiSpec - + EthTransactions - + EthBlocks - + EthState - + EthCall - + EthFees - + Trace - + LoadReceipt, + Self: FullEthApi, { /// Handler for: `eth_protocolVersion` async fn protocol_version(&self) -> RpcResult { diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs index 321e9b03e..d7d31320c 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -36,7 +36,7 @@ pub use signer::EthSigner; pub use spec::EthApiSpec; pub use state::{EthState, LoadState}; pub use trace::Trace; -pub use transaction::{EthTransactions, LoadTransaction}; +pub use transaction::{EthTransactions, LoadTransaction, UpdateRawTxForwarder}; /// Extension trait that bundles traits needed for tracing transactions. pub trait TraceExt: @@ -45,3 +45,21 @@ pub trait TraceExt: } impl TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock + Trace + Call {} + +/// Helper trait to unify all `eth` rpc server building block traits, for simplicity. +pub trait FullEthApi: + EthApiSpec + EthTransactions + EthBlocks + EthState + EthCall + EthFees + Trace + LoadReceipt +{ +} + +impl FullEthApi for T where + T: EthApiSpec + + EthTransactions + + EthBlocks + + EthState + + EthCall + + EthFees + + Trace + + LoadReceipt +{ +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index acf0156c6..0402200ce 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -1,7 +1,7 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. -use std::{fmt, sync::Arc}; +use std::{fmt, ops::Deref, sync::Arc}; use alloy_dyn_abi::TypedData; use futures::Future; @@ -648,3 +648,21 @@ pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static { /// Forwards raw transaction bytes for `eth_sendRawTransaction` async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>; } + +/// Configure server's forwarder for `eth_sendRawTransaction`, at runtime. +pub trait UpdateRawTxForwarder { + /// Sets a forwarder for `eth_sendRawTransaction` + /// + /// Note: this might be removed in the future in favor of a more generic approach. + fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc); +} + +impl UpdateRawTxForwarder for T +where + T: Deref>, + K: UpdateRawTxForwarder, +{ + fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { + self.deref().deref().set_eth_raw_transaction_forwarder(forwarder); + } +} diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs index 922c6ed77..1aed94d5c 100644 --- a/crates/rpc/rpc-eth-api/src/lib.rs +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -19,7 +19,7 @@ pub mod helpers; pub mod pubsub; pub use bundle::{EthBundleApiServer, EthCallBundleApiServer}; -pub use core::EthApiServer; +pub use core::{EthApiServer, FullEthApiServer}; pub use filter::EthFilterApiServer; pub use pubsub::EthPubSubApiServer; diff --git a/crates/rpc/rpc-eth-types/src/cache/config.rs b/crates/rpc/rpc-eth-types/src/cache/config.rs index c2d379652..64999bd6b 100644 --- a/crates/rpc/rpc-eth-types/src/cache/config.rs +++ b/crates/rpc/rpc-eth-types/src/cache/config.rs @@ -8,7 +8,7 @@ use reth_rpc_server_types::constants::cache::{ }; /// Settings for the [`EthStateCache`](super::EthStateCache). -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EthStateCacheConfig { /// Max number of blocks in cache. diff --git a/crates/rpc/rpc-eth-types/src/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs index 6f84511aa..fef2dc9ea 100644 --- a/crates/rpc/rpc-eth-types/src/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -168,7 +168,7 @@ impl FeeHistoryCache { } /// Settings for the [`FeeHistoryCache`]. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct FeeHistoryCacheConfig { /// Max number of blocks in cache. diff --git a/crates/rpc/rpc-eth-types/src/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs index 4993c5d78..92226748c 100644 --- a/crates/rpc/rpc-eth-types/src/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -24,7 +24,7 @@ use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError}; pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(constants::gas_oracle::RPC_DEFAULT_GAS_CAP); /// Settings for the [`GasPriceOracle`] -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct GasPriceOracleConfig { /// The number of populated blocks to produce the gas price estimate diff --git a/crates/rpc/rpc-eth-types/src/lib.rs b/crates/rpc/rpc-eth-types/src/lib.rs index be4e1619c..fb9901dd0 100644 --- a/crates/rpc/rpc-eth-types/src/lib.rs +++ b/crates/rpc/rpc-eth-types/src/lib.rs @@ -26,7 +26,9 @@ pub use cache::{ }; pub use error::{EthApiError, EthResult, RevertError, RpcInvalidTransactionError, SignError}; pub use fee_history::{FeeHistoryCache, FeeHistoryCacheConfig, FeeHistoryEntry}; -pub use gas_oracle::{GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult}; +pub use gas_oracle::{ + GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult, RPC_DEFAULT_GAS_CAP, +}; pub use id_provider::EthSubscriptionIdProvider; pub use logs_utils::EthFilterError; pub use pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 118a9a821..df6787199 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -71,6 +71,7 @@ futures.workspace = true rand.workspace = true serde.workspace = true thiserror.workspace = true +derive_more.workspace = true [dev-dependencies] reth-evm-ethereum.workspace = true diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index f2eb81851..e876faca8 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -3,10 +3,11 @@ use std::sync::Arc; +use derive_more::Deref; use reth_primitives::{BlockNumberOrTag, U256}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider}; use reth_rpc_eth_api::{ - helpers::{EthSigner, SpawnBlocking}, + helpers::{transaction::UpdateRawTxForwarder, EthSigner, SpawnBlocking}, RawTransactionForwarder, }; use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock}; @@ -24,6 +25,7 @@ use crate::eth::DevSigner; /// separately in submodules. The rpc handler implementation can then delegate to the main impls. /// This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone or in other /// network handlers (for example ipc). +#[derive(Deref)] pub struct EthApi { /// All nested fields bundled together. pub(super) inner: Arc>, @@ -302,6 +304,14 @@ impl EthApiInner UpdateRawTxForwarder + for EthApiInner +{ + fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { + self.raw_transaction_forwarder.write().replace(forwarder); + } +} + #[cfg(test)] mod tests { use jsonrpsee_types::error::INVALID_PARAMS_CODE; diff --git a/crates/storage/db-api/src/lib.rs b/crates/storage/db-api/src/lib.rs index dc7ab0eb4..cd25b3c65 100644 --- a/crates/storage/db-api/src/lib.rs +++ b/crates/storage/db-api/src/lib.rs @@ -79,3 +79,5 @@ pub mod models; mod scale; mod utils; + +pub use database::Database; diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index d52da187f..5ffdfedc5 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,11 +1,8 @@ -use crate::{ - traits::{BlockSource, ReceiptProvider}, - AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, - ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, PruneCheckpointReader, - ReceiptProviderIdExt, RequestsProvider, StageCheckpointReader, StateProvider, StateProviderBox, - StateProviderFactory, StateRootProvider, TransactionVariant, TransactionsProvider, - WithdrawalsProvider, +use std::{ + ops::{RangeBounds, RangeInclusive}, + sync::Arc, }; + use reth_chainspec::{ChainInfo, ChainSpec, MAINNET}; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; @@ -23,9 +20,17 @@ use revm::{ db::BundleState, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, }; -use std::{ - ops::{RangeBounds, RangeInclusive}, - sync::Arc, +use tokio::sync::broadcast; + +use crate::{ + providers::StaticFileProvider, + traits::{BlockSource, ReceiptProvider}, + AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, + CanonStateNotifications, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, + EvmEnvProvider, HeaderProvider, PruneCheckpointReader, ReceiptProviderIdExt, RequestsProvider, + StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, + StateRootProvider, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, + WithdrawalsProvider, }; /// Supports various api interfaces for testing purposes. @@ -465,3 +470,15 @@ impl PruneCheckpointReader for NoopProvider { Ok(None) } } + +impl StaticFileProviderFactory for NoopProvider { + fn static_file_provider(&self) -> StaticFileProvider { + StaticFileProvider::default() + } +} + +impl CanonStateSubscriptions for NoopProvider { + fn subscribe_to_canonical_state(&self) -> CanonStateNotifications { + broadcast::channel(1).1 + } +} diff --git a/crates/storage/provider/src/traits/full.rs b/crates/storage/provider/src/traits/full.rs index 6b35d6b25..c53150560 100644 --- a/crates/storage/provider/src/traits/full.rs +++ b/crates/storage/provider/src/traits/full.rs @@ -2,8 +2,8 @@ use crate::{ AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - DatabaseProviderFactory, EvmEnvProvider, StageCheckpointReader, StateProviderFactory, - StaticFileProviderFactory, + DatabaseProviderFactory, EvmEnvProvider, HeaderProvider, StageCheckpointReader, + StateProviderFactory, StaticFileProviderFactory, TransactionsProvider, }; use reth_db_api::database::Database; @@ -41,3 +41,31 @@ impl FullProvider for T where + 'static { } + +/// Helper trait to unify all provider traits required to support `eth` RPC server behaviour, for +/// simplicity. +pub trait FullRpcProvider: + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + BlockReaderIdExt + + HeaderProvider + + TransactionsProvider + + Clone + + Unpin + + 'static +{ +} + +impl FullRpcProvider for T where + T: StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + BlockReaderIdExt + + HeaderProvider + + TransactionsProvider + + Clone + + Unpin + + 'static +{ +} diff --git a/crates/storage/provider/src/traits/mod.rs b/crates/storage/provider/src/traits/mod.rs index bf69eda03..16071edff 100644 --- a/crates/storage/provider/src/traits/mod.rs +++ b/crates/storage/provider/src/traits/mod.rs @@ -43,7 +43,7 @@ mod stats; pub use stats::StatsReader; mod full; -pub use full::FullProvider; +pub use full::{FullProvider, FullRpcProvider}; mod tree_viewer; pub use tree_viewer::TreeViewer; diff --git a/examples/custom-dev-node/src/main.rs b/examples/custom-dev-node/src/main.rs index 24e7b229f..176e4c503 100644 --- a/examples/custom-dev-node/src/main.rs +++ b/examples/custom-dev-node/src/main.rs @@ -27,7 +27,7 @@ async fn main() -> eyre::Result<()> { .with_rpc(RpcServerArgs::default().with_http()) .with_chain(custom_chain()); - let NodeHandle { mut node, node_exit_future: _ } = NodeBuilder::new(node_config) + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) .testing_node(tasks.executor()) .node(EthereumNode::default()) .launch() diff --git a/examples/custom-inspector/src/main.rs b/examples/custom-inspector/src/main.rs index fd1d82b59..b6721eded 100644 --- a/examples/custom-inspector/src/main.rs +++ b/examples/custom-inspector/src/main.rs @@ -31,14 +31,14 @@ fn main() { Cli::::parse() .run(|builder, args| async move { // launch the node - let NodeHandle { mut node, node_exit_future } = + let NodeHandle { node, node_exit_future } = builder.node(EthereumNode::default()).launch().await?; // create a new subscription to pending transactions let mut pending_transactions = node.pool.new_pending_pool_transactions_listener(); // get an instance of the `trace_` API handler - let eth_api = node.rpc_registry.eth_api(); + let eth_api = node.rpc_registry.eth_api().clone(); println!("Spawning trace task!"); diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs index 904477905..6d18640f7 100644 --- a/examples/rpc-db/src/main.rs +++ b/examples/rpc-db/src/main.rs @@ -12,6 +12,8 @@ //! cast rpc myrpcExt_customMethod //! ``` +use std::{path::Path, sync::Arc}; + use reth::{ providers::{ providers::{BlockchainProvider, StaticFileProvider}, @@ -25,7 +27,7 @@ use reth_db_api::models::ClientVersion; // Bringing up the RPC use reth::rpc::builder::{ - RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, + EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, }; // Configuring the network parts, ideally also wouldn't need to think about this. use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; @@ -34,7 +36,6 @@ use reth::{ tasks::TokioTaskExecutor, }; use reth_node_ethereum::EthEvmConfig; -use std::{path::Path, sync::Arc}; // Custom rpc extension pub mod myrpc_ext; @@ -71,7 +72,7 @@ async fn main() -> eyre::Result<()> { // Pick which namespaces to expose. let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); - let mut server = rpc_builder.build(config); + let mut server = rpc_builder.build(config, EthApiBuild::build); // Add a custom rpc namespace let custom_rpc = MyRpcExt { provider }; diff --git a/examples/txpool-tracing/src/main.rs b/examples/txpool-tracing/src/main.rs index 85a5b795a..c9a14dee1 100644 --- a/examples/txpool-tracing/src/main.rs +++ b/examples/txpool-tracing/src/main.rs @@ -28,7 +28,7 @@ fn main() { Cli::::parse() .run(|builder, args| async move { // launch the node - let NodeHandle { mut node, node_exit_future } = + let NodeHandle { node, node_exit_future } = builder.node(EthereumNode::default()).launch().await?; // create a new subscription to pending transactions