From b4124dd1b033407a4defbf1c7173918ddb44a241 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 5 Dec 2024 17:14:51 +0400 Subject: [PATCH] feat: make RPC cache generic over primitives (#13146) --- Cargo.lock | 1 + crates/optimism/evm/Cargo.toml | 2 + crates/optimism/evm/src/l1.rs | 6 +- crates/optimism/rpc/src/eth/block.rs | 8 +- crates/optimism/rpc/src/eth/call.rs | 9 +- crates/optimism/rpc/src/eth/mod.rs | 50 +++--- crates/optimism/rpc/src/eth/transaction.rs | 12 +- crates/rpc/rpc-builder/src/eth.rs | 4 +- crates/rpc/rpc-builder/src/lib.rs | 7 +- .../rpc-eth-api/src/helpers/transaction.rs | 14 +- crates/rpc/rpc-eth-api/src/node.rs | 7 +- crates/rpc/rpc-eth-types/src/builder/ctx.rs | 28 +-- crates/rpc/rpc-eth-types/src/cache/mod.rs | 163 +++++++++--------- crates/rpc/rpc-eth-types/src/fee_history.rs | 73 ++++---- crates/rpc/rpc-eth-types/src/gas_oracle.rs | 50 +++--- crates/rpc/rpc-eth-types/src/logs_utils.rs | 20 ++- crates/rpc/rpc/src/eth/core.rs | 47 +++-- crates/rpc/rpc/src/eth/filter.rs | 25 ++- crates/rpc/rpc/src/eth/helpers/block.rs | 9 +- crates/rpc/rpc/src/eth/helpers/call.rs | 14 +- crates/rpc/rpc/src/eth/helpers/fees.rs | 10 +- .../rpc/rpc/src/eth/helpers/pending_block.rs | 4 +- crates/rpc/rpc/src/eth/helpers/receipt.rs | 3 +- crates/rpc/rpc/src/eth/helpers/signer.rs | 3 + crates/rpc/rpc/src/eth/helpers/spec.rs | 3 +- crates/rpc/rpc/src/eth/helpers/state.rs | 25 +-- crates/rpc/rpc/src/eth/helpers/trace.rs | 6 +- crates/rpc/rpc/src/eth/helpers/transaction.rs | 11 +- crates/storage/storage-api/src/block.rs | 3 + crates/storage/storage-api/src/receipts.rs | 6 +- .../storage/storage-api/src/transactions.rs | 5 +- 31 files changed, 354 insertions(+), 274 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df7737b06b81..666293e58e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8382,6 +8382,7 @@ dependencies = [ "reth-optimism-forks", "reth-optimism-primitives", "reth-primitives", + "reth-primitives-traits", "reth-prune-types", "reth-revm", "revm", diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index ab22e3e3e813..7afb3b50e676 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -16,6 +16,7 @@ reth-chainspec.workspace = true reth-ethereum-forks.workspace = true reth-evm.workspace = true reth-primitives.workspace = true +reth-primitives-traits.workspace = true reth-revm.workspace = true reth-execution-errors.workspace = true reth-execution-types.workspace = true @@ -63,6 +64,7 @@ std = [ "alloy-genesis/std", "alloy-primitives/std", "revm-primitives/std", + "reth-primitives-traits/std", "revm/std", "reth-optimism-primitives/std", "reth-ethereum-forks/std", diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index ef8c3f3b3dbe..1194dd63c2b1 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -8,7 +8,7 @@ use reth_chainspec::ChainSpec; use reth_execution_errors::BlockExecutionError; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_forks::OpHardfork; -use reth_primitives::BlockBody; +use reth_primitives_traits::BlockBody; use revm::{ primitives::{Bytecode, HashMap, SpecId}, DatabaseCommit, L1BlockInfo, @@ -32,9 +32,9 @@ const L1_BLOCK_ECOTONE_SELECTOR: [u8; 4] = hex!("440a5e20"); /// transaction in the L2 block. /// /// Returns an error if the L1 info transaction is not found, if the block is empty. -pub fn extract_l1_info(body: &BlockBody) -> Result { +pub fn extract_l1_info(body: &B) -> Result { let l1_info_tx_data = body - .transactions + .transactions() .first() .ok_or_else(|| OpBlockExecutionError::L1BlockInfoError { message: "could not find l1 block info tx in the L2 block".to_string(), diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index 92b4353ec9e4..a37a8a152640 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -9,10 +9,10 @@ use reth_primitives::TransactionMeta; use reth_provider::HeaderProvider; use reth_rpc_eth_api::{ helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, - RpcNodeCore, RpcReceipt, + RpcReceipt, }; -use crate::{OpEthApi, OpEthApiError, OpReceiptBuilder}; +use crate::{eth::OpNodeCore, OpEthApi, OpEthApiError, OpReceiptBuilder}; impl EthBlocks for OpEthApi where @@ -20,7 +20,7 @@ where Error = OpEthApiError, NetworkTypes: Network, >, - N: RpcNodeCore + HeaderProvider>, + N: OpNodeCore + HeaderProvider>, { async fn block_receipts( &self, @@ -77,6 +77,6 @@ where impl LoadBlock for OpEthApi where Self: LoadPendingBlock + SpawnBlocking, - N: RpcNodeCore, + N: OpNodeCore, { } diff --git a/crates/optimism/rpc/src/eth/call.rs b/crates/optimism/rpc/src/eth/call.rs index c5e96bb87d17..c9d874f7392a 100644 --- a/crates/optimism/rpc/src/eth/call.rs +++ b/crates/optimism/rpc/src/eth/call.rs @@ -1,3 +1,4 @@ +use super::OpNodeCore; use crate::{OpEthApi, OpEthApiError}; use alloy_consensus::Header; use alloy_primitives::{Bytes, TxKind, U256}; @@ -5,7 +6,7 @@ use alloy_rpc_types_eth::transaction::TransactionRequest; use reth_evm::ConfigureEvm; use reth_rpc_eth_api::{ helpers::{estimate::EstimateCall, Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking}, - FromEthApiError, IntoEthApiError, RpcNodeCore, + FromEthApiError, IntoEthApiError, }; use reth_rpc_eth_types::{revm_utils::CallFees, RpcInvalidTransactionError}; use revm::primitives::{BlockEnv, OptimismFields, TxEnv}; @@ -13,7 +14,7 @@ use revm::primitives::{BlockEnv, OptimismFields, TxEnv}; impl EthCall for OpEthApi where Self: EstimateCall + LoadPendingBlock, - N: RpcNodeCore, + N: OpNodeCore, { } @@ -21,7 +22,7 @@ impl EstimateCall for OpEthApi where Self: Call, Self::Error: From, - N: RpcNodeCore, + N: OpNodeCore, { } @@ -29,7 +30,7 @@ impl Call for OpEthApi where Self: LoadState> + SpawnBlocking, Self::Error: From, - N: RpcNodeCore, + N: OpNodeCore, { #[inline] fn call_gas_limit(&self) -> u64 { diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 27672804839b..0e657bf0440f 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -8,6 +8,7 @@ mod call; mod pending_block; pub use receipt::{OpReceiptBuilder, OpReceiptFieldsBuilder}; +use reth_node_api::NodePrimitives; use reth_optimism_primitives::OpPrimitives; use std::{fmt, sync::Arc}; @@ -21,7 +22,8 @@ use reth_network_api::NetworkInfo; use reth_node_builder::EthApiBuilderCtx; use reth_provider::{ BlockNumReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, - EvmEnvProvider, StageCheckpointReader, StateProviderFactory, + EvmEnvProvider, NodePrimitivesProvider, ProviderBlock, ProviderReceipt, StageCheckpointReader, + StateProviderFactory, }; use reth_rpc::eth::{core::EthApiInner, DevSigner}; use reth_rpc_eth_api::{ @@ -48,6 +50,10 @@ pub type EthApiNodeBackend = EthApiInner< ::Evm, >; +/// A helper trait with requirements for [`RpcNodeCore`] to be used in [`OpEthApi`]. +pub trait OpNodeCore: RpcNodeCore {} +impl OpNodeCore for T where T: RpcNodeCore {} + /// OP-Reth `Eth` API implementation. /// /// This type provides the functionality for handling `eth_` related requests. @@ -59,14 +65,14 @@ pub type EthApiNodeBackend = EthApiInner< /// This type implements the [`FullEthApi`](reth_rpc_eth_api::helpers::FullEthApi) by implemented /// all the `Eth` helper traits and prerequisite traits. #[derive(Clone)] -pub struct OpEthApi { +pub struct OpEthApi { /// Gateway to node's core components. inner: Arc>, } impl OpEthApi where - N: RpcNodeCore< + N: OpNodeCore< Provider: BlockReaderIdExt + ChainSpecProvider + CanonStateSubscriptions @@ -83,7 +89,7 @@ where impl EthApiTypes for OpEthApi where Self: Send + Sync, - N: RpcNodeCore, + N: OpNodeCore, { type Error = OpEthApiError; type NetworkTypes = Optimism; @@ -96,7 +102,7 @@ where impl RpcNodeCore for OpEthApi where - N: RpcNodeCore, + N: OpNodeCore, { type Provider = N::Provider; type Pool = N::Pool; @@ -132,17 +138,17 @@ where impl RpcNodeCoreExt for OpEthApi where - N: RpcNodeCore, + N: OpNodeCore, { #[inline] - fn cache(&self) -> &EthStateCache { + fn cache(&self) -> &EthStateCache, ProviderReceipt> { self.inner.eth_api.cache() } } impl EthApiSpec for OpEthApi where - N: RpcNodeCore< + N: OpNodeCore< Provider: ChainSpecProvider + BlockNumReader + StageCheckpointReader, @@ -163,7 +169,7 @@ where impl SpawnBlocking for OpEthApi where Self: Send + Sync + Clone + 'static, - N: RpcNodeCore, + N: OpNodeCore, { #[inline] fn io_task_spawner(&self) -> impl TaskSpawner { @@ -184,7 +190,7 @@ where impl LoadFee for OpEthApi where Self: LoadBlock, - N: RpcNodeCore< + N: OpNodeCore< Provider: BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider @@ -203,7 +209,7 @@ where } impl LoadState for OpEthApi where - N: RpcNodeCore< + N: OpNodeCore< Provider: StateProviderFactory + ChainSpecProvider, Pool: TransactionPool, > @@ -213,7 +219,7 @@ impl LoadState for OpEthApi where impl EthState for OpEthApi where Self: LoadState + SpawnBlocking, - N: RpcNodeCore, + N: OpNodeCore, { #[inline] fn max_proof_window(&self) -> u64 { @@ -224,27 +230,27 @@ where impl EthFees for OpEthApi where Self: LoadFee, - N: RpcNodeCore, + N: OpNodeCore, { } impl Trace for OpEthApi where Self: RpcNodeCore + LoadState>, - N: RpcNodeCore, + N: OpNodeCore, { } impl AddDevSigners for OpEthApi where - N: RpcNodeCore, + N: OpNodeCore, { fn with_dev_accounts(&self) { *self.inner.eth_api.signers().write() = DevSigner::random_signers(20) } } -impl fmt::Debug for OpEthApi { +impl fmt::Debug for OpEthApi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OpEthApi").finish_non_exhaustive() } @@ -252,7 +258,7 @@ impl fmt::Debug for OpEthApi { /// Container type `OpEthApi` #[allow(missing_debug_implementations)] -struct OpEthApiInner { +struct OpEthApiInner { /// Gateway to node's core components. eth_api: EthApiNodeBackend, /// Sequencer client, configured to forward submitted transactions to sequencer of given OP @@ -285,10 +291,12 @@ impl OpEthApiBuilder { /// Builds an instance of [`OpEthApi`] pub fn build(self, ctx: &EthApiBuilderCtx) -> OpEthApi where - N: RpcNodeCore< - Provider: BlockReaderIdExt - + ChainSpecProvider - + CanonStateSubscriptions + N: OpNodeCore< + Provider: BlockReaderIdExt< + Block = <::Primitives as NodePrimitives>::Block, + Receipt = <::Primitives as NodePrimitives>::Receipt, + > + ChainSpecProvider + + CanonStateSubscriptions + Clone + 'static, >, diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index 3ba5edead55a..b5d4ce2bc555 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -10,17 +10,17 @@ use reth_primitives::{RecoveredTx, TransactionSigned}; use reth_provider::{BlockReaderIdExt, ReceiptProvider, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, - FromEthApiError, FullEthApiTypes, RpcNodeCore, TransactionCompat, + FromEthApiError, FullEthApiTypes, RpcNodeCore, RpcNodeCoreExt, TransactionCompat, }; use reth_rpc_eth_types::utils::recover_raw_transaction; use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; -use crate::{OpEthApi, OpEthApiError, SequencerClient}; +use crate::{eth::OpNodeCore, OpEthApi, OpEthApiError, SequencerClient}; impl EthTransactions for OpEthApi where Self: LoadTransaction, - N: RpcNodeCore, + N: OpNodeCore, { fn signers(&self) -> &parking_lot::RwLock>> { self.inner.eth_api.signers() @@ -56,15 +56,15 @@ where impl LoadTransaction for OpEthApi where - Self: SpawnBlocking + FullEthApiTypes, - N: RpcNodeCore, + Self: SpawnBlocking + FullEthApiTypes + RpcNodeCoreExt, + N: OpNodeCore, Self::Pool: TransactionPool, { } impl OpEthApi where - N: RpcNodeCore, + N: OpNodeCore, { /// Returns the [`SequencerClient`] if one is set. pub fn raw_tx_forwarder(&self) -> Option { diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 283fba6e957f..453efb0ddb4a 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -15,11 +15,11 @@ pub type DynEthApiBuilder { +pub struct EthHandlers { /// Main `eth_` request handler pub api: EthApi, /// The async caching layer used by the eth handlers - pub cache: EthStateCache, + 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) diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 031f960096fa..1d8bfb9c2972 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -925,7 +925,7 @@ impl RpcModuleConfigBuilder { /// A Helper type the holds instances of the configured modules. #[derive(Debug, Clone)] pub struct RpcRegistryInner< - Provider, + Provider: BlockReader, Pool, Network, Tasks, @@ -1029,6 +1029,7 @@ where impl RpcRegistryInner where + Provider: BlockReader, EthApi: EthApiTypes, { /// Returns a reference to the installed [`EthApi`](reth_rpc::eth::EthApi). @@ -1045,7 +1046,7 @@ where /// /// This will spawn exactly one [`EthStateCache`] service if this is the first time the cache is /// requested. - pub const fn eth_cache(&self) -> &EthStateCache { + pub const fn eth_cache(&self) -> &EthStateCache { &self.eth.cache } @@ -1089,7 +1090,7 @@ impl where Network: NetworkInfo + Clone + 'static, EthApi: EthApiTypes, - Provider: ChainSpecProvider, + Provider: BlockReader + ChainSpecProvider, BlockExecutor: BlockExecutorProvider, { /// Instantiates `AdminApi` diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 3b4ecb9de273..f73d761600e8 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -8,12 +8,13 @@ use alloy_network::TransactionBuilder; use alloy_primitives::{Address, Bytes, TxHash, B256}; use alloy_rpc_types_eth::{transaction::TransactionRequest, BlockNumberOrTag, TransactionInfo}; use futures::Future; +use reth_node_api::BlockBody; use reth_primitives::{ transaction::SignedTransactionIntoRecoveredExt, SealedBlockWithSenders, TransactionMeta, TransactionSigned, }; use reth_provider::{ - BlockNumReader, BlockReaderIdExt, ProviderReceipt, ProviderTx, ReceiptProvider, + BlockNumReader, BlockReaderIdExt, ProviderBlock, ProviderReceipt, ProviderTx, ReceiptProvider, TransactionsProvider, }; use reth_rpc_eth_types::{ @@ -79,15 +80,17 @@ pub trait EthTransactions: LoadTransaction { /// Get all transactions in the block with the given hash. /// /// Returns `None` if block does not exist. + #[expect(clippy::type_complexity)] fn transactions_by_block( &self, block: B256, - ) -> impl Future>, Self::Error>> + Send { + ) -> impl Future>>, Self::Error>> + Send + { async move { self.cache() .get_sealed_block_with_senders(block) .await - .map(|b| b.map(|b| b.body.transactions.clone())) + .map(|b| b.map(|b| b.body.transactions().to_vec())) .map_err(Self::Error::from_eth_err) } } @@ -568,7 +571,10 @@ pub trait LoadTransaction: SpawnBlocking + FullEthApiTypes + RpcNodeCoreExt { hash: B256, ) -> impl Future< Output = Result< - Option<(TransactionSource>, Arc)>, + Option<( + TransactionSource>, + Arc>>, + )>, Self::Error, >, > + Send { diff --git a/crates/rpc/rpc-eth-api/src/node.rs b/crates/rpc/rpc-eth-api/src/node.rs index 12dbe8f66641..538cb2ead8a3 100644 --- a/crates/rpc/rpc-eth-api/src/node.rs +++ b/crates/rpc/rpc-eth-api/src/node.rs @@ -1,6 +1,7 @@ //! Helper trait for interfacing with [`FullNodeComponents`]. use reth_node_api::FullNodeComponents; +use reth_provider::{BlockReader, ProviderBlock, ProviderReceipt}; use reth_rpc_eth_types::EthStateCache; /// Helper trait to relax trait bounds on [`FullNodeComponents`]. @@ -76,7 +77,9 @@ where /// Additional components, asides the core node components, needed to run `eth_` namespace API /// server. -pub trait RpcNodeCoreExt: RpcNodeCore { +pub trait RpcNodeCoreExt: RpcNodeCore { /// Returns handle to RPC cache service. - fn cache(&self) -> &EthStateCache; + fn cache( + &self, + ) -> &EthStateCache, ProviderReceipt>; } diff --git a/crates/rpc/rpc-eth-types/src/builder/ctx.rs b/crates/rpc/rpc-eth-types/src/builder/ctx.rs index db2beb4a4549..f9710882f2be 100644 --- a/crates/rpc/rpc-eth-types/src/builder/ctx.rs +++ b/crates/rpc/rpc-eth-types/src/builder/ctx.rs @@ -3,7 +3,7 @@ use reth_chain_state::CanonStateSubscriptions; use reth_chainspec::ChainSpecProvider; use reth_primitives::NodePrimitives; -use reth_storage_api::BlockReaderIdExt; +use reth_storage_api::{BlockReader, BlockReaderIdExt}; use reth_tasks::TaskSpawner; use crate::{ @@ -13,7 +13,10 @@ use crate::{ /// Context for building the `eth` namespace API. #[derive(Debug, Clone)] -pub struct EthApiBuilderCtx { +pub struct EthApiBuilderCtx +where + Provider: BlockReader, +{ /// Database handle. pub provider: Provider, /// Mempool handle. @@ -29,7 +32,7 @@ pub struct EthApiBuilderCtx { /// Events handle. pub events: Events, /// RPC cache handle. - pub cache: EthStateCache, + pub cache: EthStateCache, } impl @@ -38,27 +41,24 @@ where Provider: BlockReaderIdExt + Clone, { /// Returns a new [`FeeHistoryCache`] for the context. - pub fn new_fee_history_cache(&self) -> FeeHistoryCache + pub fn new_fee_history_cache(&self) -> FeeHistoryCache where - Provider: ChainSpecProvider + 'static, + N: NodePrimitives, Tasks: TaskSpawner, - Events: CanonStateSubscriptions< - Primitives: NodePrimitives< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - >, - >, + Events: CanonStateSubscriptions, + Provider: + BlockReaderIdExt + ChainSpecProvider + 'static, { - let fee_history_cache = - FeeHistoryCache::new(self.cache.clone(), self.config.fee_history_cache); + let fee_history_cache = FeeHistoryCache::new(self.config.fee_history_cache); let new_canonical_blocks = self.events.canonical_state_stream(); let fhc = fee_history_cache.clone(); let provider = self.provider.clone(); + let cache = self.cache.clone(); self.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_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await; }), ); diff --git a/crates/rpc/rpc-eth-types/src/cache/mod.rs b/crates/rpc/rpc-eth-types/src/cache/mod.rs index 7a0d9dfa0f01..168638872407 100644 --- a/crates/rpc/rpc-eth-types/src/cache/mod.rs +++ b/crates/rpc/rpc-eth-types/src/cache/mod.rs @@ -1,14 +1,14 @@ //! Async caching support for eth RPC use super::{EthStateCacheConfig, MultiConsumerLruCache}; -use alloy_consensus::Header; use alloy_eips::BlockHashOrNumber; use alloy_primitives::B256; use futures::{future::Either, Stream, StreamExt}; use reth_chain_state::CanonStateNotification; use reth_errors::{ProviderError, ProviderResult}; use reth_execution_types::Chain; -use reth_primitives::{Receipt, SealedBlockWithSenders, TransactionSigned}; +use reth_primitives::{NodePrimitives, SealedBlockWithSenders}; +use reth_primitives_traits::{Block, BlockBody}; use reth_storage_api::{BlockReader, StateProviderFactory, TransactionVariant}; use reth_tasks::{TaskSpawner, TokioTaskExecutor}; use schnellru::{ByLength, Limiter}; @@ -30,41 +30,49 @@ pub mod metrics; pub mod multi_consumer; /// The type that can send the response to a requested [`SealedBlockWithSenders`] -type BlockTransactionsResponseSender = - oneshot::Sender>>>; +type BlockTransactionsResponseSender = oneshot::Sender>>>; /// The type that can send the response to a requested [`SealedBlockWithSenders`] -type BlockWithSendersResponseSender = - oneshot::Sender>>>; +type BlockWithSendersResponseSender = + oneshot::Sender>>>>; /// The type that can send the response to the requested receipts of a block. -type ReceiptsResponseSender = oneshot::Sender>>>>; +type ReceiptsResponseSender = oneshot::Sender>>>>; /// The type that can send the response to a requested header -type HeaderResponseSender = oneshot::Sender>; +type HeaderResponseSender = oneshot::Sender>; -type BlockLruCache = MultiConsumerLruCache< +type BlockLruCache = MultiConsumerLruCache< B256, - Arc, + Arc>, L, - Either, + Either< + BlockWithSendersResponseSender, + BlockTransactionsResponseSender<<::Body as BlockBody>::Transaction>, + >, >; -type ReceiptsLruCache = - MultiConsumerLruCache>, L, ReceiptsResponseSender>; +type ReceiptsLruCache = + MultiConsumerLruCache>, L, ReceiptsResponseSender>; -type HeaderLruCache = MultiConsumerLruCache; +type HeaderLruCache = MultiConsumerLruCache>; /// Provides async access to cached eth data /// /// This is the frontend for the async caching service which manages cached data on a different /// task. -#[derive(Debug, Clone)] -pub struct EthStateCache { - to_service: UnboundedSender, +#[derive(Debug)] +pub struct EthStateCache { + to_service: UnboundedSender>, } -impl EthStateCache { +impl Clone for EthStateCache { + fn clone(&self) -> Self { + Self { to_service: self.to_service.clone() } + } +} + +impl EthStateCache { /// Creates and returns both [`EthStateCache`] frontend and the memory bound service. fn create( provider: Provider, @@ -73,7 +81,10 @@ impl EthStateCache { max_receipts: u32, max_headers: u32, max_concurrent_db_operations: usize, - ) -> (Self, EthStateCacheService) { + ) -> (Self, EthStateCacheService) + where + Provider: BlockReader, + { let (to_service, rx) = unbounded_channel(); let service = EthStateCacheService { provider, @@ -95,14 +106,8 @@ impl EthStateCache { /// See also [`Self::spawn_with`] pub fn spawn(provider: Provider, config: EthStateCacheConfig) -> Self where - Provider: StateProviderFactory - + BlockReader< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - Header = reth_primitives::Header, - > + Clone - + Unpin - + 'static, + Provider: + StateProviderFactory + BlockReader + Clone + Unpin + 'static, { Self::spawn_with(provider, config, TokioTaskExecutor::default()) } @@ -117,14 +122,8 @@ impl EthStateCache { executor: Tasks, ) -> Self where - Provider: StateProviderFactory - + BlockReader< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - Header = reth_primitives::Header, - > + Clone - + Unpin - + 'static, + Provider: + StateProviderFactory + BlockReader + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, { let EthStateCacheConfig { @@ -151,19 +150,16 @@ impl EthStateCache { pub async fn get_sealed_block_with_senders( &self, block_hash: B256, - ) -> ProviderResult>> { + ) -> ProviderResult>>> { let (response_tx, rx) = oneshot::channel(); let _ = self.to_service.send(CacheAction::GetBlockWithSenders { block_hash, response_tx }); rx.await.map_err(|_| ProviderError::CacheServiceUnavailable)? } - /// Requests the [Receipt] for the block hash + /// Requests the receipts for the block hash /// /// Returns `None` if the block was not found. - pub async fn get_receipts( - &self, - block_hash: B256, - ) -> ProviderResult>>> { + pub async fn get_receipts(&self, block_hash: B256) -> ProviderResult>>> { let (response_tx, rx) = oneshot::channel(); let _ = self.to_service.send(CacheAction::GetReceipts { block_hash, response_tx }); rx.await.map_err(|_| ProviderError::CacheServiceUnavailable)? @@ -173,7 +169,7 @@ impl EthStateCache { pub async fn get_block_and_receipts( &self, block_hash: B256, - ) -> ProviderResult, Arc>)>> { + ) -> ProviderResult>, Arc>)>> { let block = self.get_sealed_block_with_senders(block_hash); let receipts = self.get_receipts(block_hash); @@ -185,7 +181,7 @@ impl EthStateCache { /// Requests the header for the given hash. /// /// Returns an error if the header is not found. - pub async fn get_header(&self, block_hash: B256) -> ProviderResult
{ + pub async fn get_header(&self, block_hash: B256) -> ProviderResult { let (response_tx, rx) = oneshot::channel(); let _ = self.to_service.send(CacheAction::GetHeader { block_hash, response_tx }); rx.await.map_err(|_| ProviderError::CacheServiceUnavailable)? @@ -216,25 +212,26 @@ pub(crate) struct EthStateCacheService< LimitReceipts = ByLength, LimitHeaders = ByLength, > where - LimitBlocks: Limiter>, - LimitReceipts: Limiter>>, - LimitHeaders: Limiter, + Provider: BlockReader, + LimitBlocks: Limiter>>, + LimitReceipts: Limiter>>, + LimitHeaders: Limiter, { /// The type used to lookup data from disk provider: Provider, /// The LRU cache for full blocks grouped by their hash. - full_block_cache: BlockLruCache, + full_block_cache: BlockLruCache, /// The LRU cache for full blocks grouped by their hash. - receipts_cache: ReceiptsLruCache, + receipts_cache: ReceiptsLruCache, /// The LRU cache for headers. /// /// Headers are cached because they are required to populate the environment for execution /// (evm). - headers_cache: HeaderLruCache, + headers_cache: HeaderLruCache, /// Sender half of the action channel. - action_tx: UnboundedSender, + action_tx: UnboundedSender>, /// Receiver half of the action channel. - action_rx: UnboundedReceiverStream, + action_rx: UnboundedReceiverStream>, /// The type that's used to spawn tasks that do the actual work action_task_spawner: Tasks, /// Rate limiter @@ -249,7 +246,7 @@ where fn on_new_block( &mut self, block_hash: B256, - res: ProviderResult>>, + res: ProviderResult>>>, ) { if let Some(queued) = self.full_block_cache.remove(&block_hash) { // send the response to queued senders @@ -260,7 +257,7 @@ where } Either::Right(transaction_tx) => { let _ = transaction_tx.send(res.clone().map(|maybe_block| { - maybe_block.map(|block| block.block.body.transactions.clone()) + maybe_block.map(|block| block.block.body.transactions().to_vec()) })); } } @@ -276,7 +273,7 @@ where fn on_new_receipts( &mut self, block_hash: B256, - res: ProviderResult>>>, + res: ProviderResult>>>, ) { if let Some(queued) = self.receipts_cache.remove(&block_hash) { // send the response to queued senders @@ -294,7 +291,7 @@ where fn on_reorg_block( &mut self, block_hash: B256, - res: ProviderResult>, + res: ProviderResult>>, ) { let res = res.map(|b| b.map(Arc::new)); if let Some(queued) = self.full_block_cache.remove(&block_hash) { @@ -306,7 +303,7 @@ where } Either::Right(transaction_tx) => { let _ = transaction_tx.send(res.clone().map(|maybe_block| { - maybe_block.map(|block| block.block.body.transactions.clone()) + maybe_block.map(|block| block.block.body.transactions().to_vec()) })); } } @@ -317,7 +314,7 @@ where fn on_reorg_receipts( &mut self, block_hash: B256, - res: ProviderResult>>>, + res: ProviderResult>>>, ) { if let Some(queued) = self.receipts_cache.remove(&block_hash) { // send the response to queued senders @@ -336,14 +333,7 @@ where impl Future for EthStateCacheService where - Provider: StateProviderFactory - + BlockReader< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - Header = reth_primitives::Header, - > + Clone - + Unpin - + 'static, + Provider: StateProviderFactory + BlockReader + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, { type Output = (); @@ -504,52 +494,55 @@ where } /// All message variants sent through the channel -enum CacheAction { +enum CacheAction { GetBlockWithSenders { block_hash: B256, - response_tx: BlockWithSendersResponseSender, + response_tx: BlockWithSendersResponseSender, }, GetHeader { block_hash: B256, - response_tx: HeaderResponseSender, + response_tx: HeaderResponseSender, }, GetReceipts { block_hash: B256, - response_tx: ReceiptsResponseSender, + response_tx: ReceiptsResponseSender, }, BlockWithSendersResult { block_hash: B256, - res: ProviderResult>>, + res: ProviderResult>>>, }, ReceiptsResult { block_hash: B256, - res: ProviderResult>>>, + res: ProviderResult>>>, }, HeaderResult { block_hash: B256, - res: Box>, + res: Box>, }, CacheNewCanonicalChain { - chain_change: ChainChange, + chain_change: ChainChange, }, RemoveReorgedChain { - chain_change: ChainChange, + chain_change: ChainChange, }, } -struct BlockReceipts { +struct BlockReceipts { block_hash: B256, - receipts: Vec>, + receipts: Vec>, } /// A change of the canonical chain -struct ChainChange { - blocks: Vec, - receipts: Vec, +struct ChainChange { + blocks: Vec>, + receipts: Vec>, } -impl ChainChange { - fn new(chain: Arc) -> Self { +impl ChainChange { + fn new(chain: Arc>) -> Self + where + N: NodePrimitives, + { let (blocks, receipts): (Vec<_>, Vec<_>) = chain .blocks_and_receipts() .map(|(block, receipts)| { @@ -566,9 +559,11 @@ impl ChainChange { /// immediately before they need to be fetched from disk. /// /// Reorged blocks are removed from the cache. -pub async fn cache_new_blocks_task(eth_state_cache: EthStateCache, mut events: St) -where - St: Stream + Unpin + 'static, +pub async fn cache_new_blocks_task( + eth_state_cache: EthStateCache, + mut events: St, +) where + St: Stream> + Unpin + 'static, { while let Some(event) = events.next().await { if let Some(reverted) = event.reverted() { diff --git a/crates/rpc/rpc-eth-types/src/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs index 35233e6c2192..2c365ae90bff 100644 --- a/crates/rpc/rpc-eth-types/src/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -6,6 +6,7 @@ use std::{ sync::{atomic::Ordering::SeqCst, Arc}, }; +use alloy_consensus::{BlockHeader, Transaction, TxReceipt}; use alloy_eips::eip1559::calc_next_block_base_fee; use alloy_primitives::B256; use alloy_rpc_types_eth::TxGasAndReward; @@ -16,8 +17,8 @@ use futures::{ use metrics::atomics::AtomicU64; use reth_chain_state::CanonStateNotification; use reth_chainspec::{ChainSpecProvider, EthChainSpec}; -use reth_primitives::{NodePrimitives, Receipt, SealedBlock, TransactionSigned}; -use reth_primitives_traits::{Block, BlockBody}; +use reth_primitives::{NodePrimitives, SealedBlock}; +use reth_primitives_traits::BlockBody; use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY; use reth_storage_api::BlockReaderIdExt; use revm_primitives::{calc_blob_gasprice, calc_excess_blob_gas}; @@ -36,13 +37,12 @@ pub struct FeeHistoryCache { impl FeeHistoryCache { /// Creates new `FeeHistoryCache` instance, initialize it with the more recent data, set bounds - pub fn new(eth_cache: EthStateCache, config: FeeHistoryCacheConfig) -> Self { + pub fn new(config: FeeHistoryCacheConfig) -> Self { let inner = FeeHistoryCacheInner { lower_bound: Default::default(), upper_bound: Default::default(), config, entries: Default::default(), - eth_cache, }; Self { inner: Arc::new(inner) } } @@ -73,9 +73,12 @@ impl FeeHistoryCache { } /// Insert block data into the cache. - async fn insert_blocks<'a, I>(&self, blocks: I) + async fn insert_blocks<'a, I, H, B, R>(&self, blocks: I) where - I: IntoIterator>)>, + H: BlockHeader + 'a, + B: BlockBody, + R: TxReceipt, + I: IntoIterator, Arc>)>, { let mut entries = self.inner.entries.write().await; @@ -87,11 +90,11 @@ impl FeeHistoryCache { &percentiles, fee_history_entry.gas_used, fee_history_entry.base_fee_per_gas, - &block.body.transactions, + block.body.transactions(), &receipts, ) .unwrap_or_default(); - entries.insert(block.number, fee_history_entry); + entries.insert(block.number(), fee_history_entry); } // enforce bounds by popping the oldest entries @@ -200,7 +203,6 @@ struct FeeHistoryCacheInner { config: FeeHistoryCacheConfig, /// Stores the entries of the cache entries: tokio::sync::RwLock>, - eth_cache: EthStateCache, } /// Awaits for new chain events and directly inserts them into the cache so they're available @@ -209,10 +211,12 @@ pub async fn fee_history_cache_new_blocks_task( fee_history_cache: FeeHistoryCache, mut events: St, provider: Provider, + cache: EthStateCache, ) where St: Stream> + Unpin + 'static, - Provider: BlockReaderIdExt + ChainSpecProvider + 'static, - N: NodePrimitives, + Provider: + BlockReaderIdExt + ChainSpecProvider + 'static, + N: NodePrimitives, { // We're listening for new blocks emitted when the node is in live sync. // If the node transitions to stage sync, we need to fetch the missing blocks @@ -225,12 +229,7 @@ pub async fn fee_history_cache_new_blocks_task( trace!(target: "rpc::fee", ?block_number, "Fetching missing block for fee history cache"); if let Ok(Some(hash)) = provider.block_hash(block_number) { // fetch missing block - fetch_missing_block = fee_history_cache - .inner - .eth_cache - .get_block_and_receipts(hash) - .boxed() - .fuse(); + fetch_missing_block = cache.get_block_and_receipts(hash).boxed().fuse(); } } } @@ -270,13 +269,17 @@ pub async fn fee_history_cache_new_blocks_task( /// the corresponding rewards for the transactions at each percentile. /// /// The results are returned as a vector of U256 values. -pub fn calculate_reward_percentiles_for_block( +pub fn calculate_reward_percentiles_for_block( percentiles: &[f64], gas_used: u64, base_fee_per_gas: u64, - transactions: &[TransactionSigned], - receipts: &[Receipt], -) -> Result, EthApiError> { + transactions: &[T], + receipts: &[R], +) -> Result, EthApiError> +where + T: Transaction, + R: TxReceipt, +{ let mut transactions = transactions .iter() .zip(receipts) @@ -287,12 +290,12 @@ pub fn calculate_reward_percentiles_for_block( // While we will sum up the gas again later, it is worth // noting that the order of the transactions will be different, // so the sum will also be different for each receipt. - let gas_used = receipt.cumulative_gas_used - *previous_gas; - *previous_gas = receipt.cumulative_gas_used; + let gas_used = receipt.cumulative_gas_used() - *previous_gas; + *previous_gas = receipt.cumulative_gas_used(); Some(TxGasAndReward { - gas_used, - reward: tx.effective_tip_per_gas(Some(base_fee_per_gas)).unwrap_or_default(), + gas_used: gas_used as u64, + reward: tx.effective_tip_per_gas(base_fee_per_gas).unwrap_or_default(), }) }) .collect::>(); @@ -361,20 +364,20 @@ impl FeeHistoryEntry { /// Creates a new entry from a sealed block. /// /// Note: This does not calculate the rewards for the block. - pub fn new(block: &SealedBlock) -> Self { + pub fn new(block: &SealedBlock) -> Self { Self { - base_fee_per_gas: block.base_fee_per_gas.unwrap_or_default(), - gas_used_ratio: block.gas_used as f64 / block.gas_limit as f64, - base_fee_per_blob_gas: block.blob_fee(), - blob_gas_used_ratio: block.body().blob_gas_used() as f64 / + base_fee_per_gas: block.base_fee_per_gas().unwrap_or_default(), + gas_used_ratio: block.gas_used() as f64 / block.gas_limit() as f64, + base_fee_per_blob_gas: block.excess_blob_gas().map(calc_blob_gasprice), + blob_gas_used_ratio: block.body.blob_gas_used() as f64 / alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, - excess_blob_gas: block.excess_blob_gas, - blob_gas_used: block.blob_gas_used, - gas_used: block.gas_used, + excess_blob_gas: block.excess_blob_gas(), + blob_gas_used: block.blob_gas_used(), + gas_used: block.gas_used(), header_hash: block.hash(), - gas_limit: block.gas_limit, + gas_limit: block.gas_limit(), rewards: Vec::new(), - timestamp: block.timestamp, + timestamp: block.timestamp(), } } diff --git a/crates/rpc/rpc-eth-types/src/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs index 73cab209fd54..ed49d7c67011 100644 --- a/crates/rpc/rpc-eth-types/src/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -1,13 +1,13 @@ //! An implementation of the eth gas price oracle, used for providing gas price estimates based on //! previous blocks. -use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader}; +use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader, Transaction}; use alloy_eips::BlockNumberOrTag; use alloy_primitives::{B256, U256}; use alloy_rpc_types_eth::BlockId; use derive_more::{Deref, DerefMut, From, Into}; use itertools::Itertools; -use reth_primitives_traits::SignedTransaction; +use reth_primitives_traits::{BlockBody, SignedTransaction}; use reth_rpc_server_types::{ constants, constants::gas_oracle::{ @@ -15,7 +15,7 @@ use reth_rpc_server_types::{ DEFAULT_MAX_GAS_PRICE, MAX_HEADER_HISTORY, SAMPLE_NUMBER, }, }; -use reth_storage_api::BlockReaderIdExt; +use reth_storage_api::{BlockReader, BlockReaderIdExt}; use schnellru::{ByLength, LruMap}; use serde::{Deserialize, Serialize}; use std::fmt::{self, Debug, Formatter}; @@ -70,11 +70,14 @@ impl Default for GasPriceOracleConfig { /// Calculates a gas price depending on recent blocks. #[derive(Debug)] -pub struct GasPriceOracle { +pub struct GasPriceOracle +where + Provider: BlockReader, +{ /// The type used to subscribe to block events and get block info provider: Provider, /// The cache for blocks - cache: EthStateCache, + cache: EthStateCache, /// The config for the oracle oracle_config: GasPriceOracleConfig, /// The price under which the sample will be ignored. @@ -92,7 +95,7 @@ where pub fn new( provider: Provider, mut oracle_config: GasPriceOracleConfig, - cache: EthStateCache, + cache: EthStateCache, ) -> Self { // sanitize the percentile to be less than 100 if oracle_config.percentile > 100 { @@ -220,43 +223,44 @@ where None => return Ok(None), }; - let base_fee_per_gas = block.base_fee_per_gas; - let parent_hash = block.parent_hash; + let base_fee_per_gas = block.base_fee_per_gas(); + let parent_hash = block.parent_hash(); // sort the functions by ascending effective tip first - let sorted_transactions = block - .body - .transactions - .iter() - .sorted_by_cached_key(|tx| tx.effective_tip_per_gas(base_fee_per_gas)); + let sorted_transactions = block.body.transactions().iter().sorted_by_cached_key(|tx| { + if let Some(base_fee) = base_fee_per_gas { + (*tx).effective_tip_per_gas(base_fee) + } else { + Some((*tx).priority_fee_or_price()) + } + }); let mut prices = Vec::with_capacity(limit); for tx in sorted_transactions { - let mut effective_gas_tip = None; + let effective_tip = if let Some(base_fee) = base_fee_per_gas { + tx.effective_tip_per_gas(base_fee) + } else { + Some(tx.priority_fee_or_price()) + }; + // ignore transactions with a tip under the configured threshold if let Some(ignore_under) = self.ignore_price { - let tip = tx.effective_tip_per_gas(base_fee_per_gas); - effective_gas_tip = Some(tip); - if tip < Some(ignore_under) { + if effective_tip < Some(ignore_under) { continue } } // check if the sender was the coinbase, if so, ignore if let Some(sender) = tx.recover_signer() { - if sender == block.beneficiary { + if sender == block.beneficiary() { continue } } // a `None` effective_gas_tip represents a transaction where the max_fee_per_gas is // less than the base fee which would be invalid - let effective_gas_tip = effective_gas_tip - .unwrap_or_else(|| tx.effective_tip_per_gas(base_fee_per_gas)) - .ok_or(RpcInvalidTransactionError::FeeCapTooLow)?; - - prices.push(U256::from(effective_gas_tip)); + prices.push(U256::from(effective_tip.ok_or(RpcInvalidTransactionError::FeeCapTooLow)?)); // we have enough entries if prices.len() >= limit { diff --git a/crates/rpc/rpc-eth-types/src/logs_utils.rs b/crates/rpc/rpc-eth-types/src/logs_utils.rs index 2e41c7a1183d..6078d32e894f 100644 --- a/crates/rpc/rpc-eth-types/src/logs_utils.rs +++ b/crates/rpc/rpc-eth-types/src/logs_utils.rs @@ -2,14 +2,15 @@ //! //! Log parsing for building filter. +use alloy_consensus::TxReceipt; use alloy_eips::{eip2718::Encodable2718, BlockNumHash}; use alloy_primitives::TxHash; use alloy_rpc_types_eth::{FilteredParams, Log}; use reth_chainspec::ChainInfo; use reth_errors::ProviderError; use reth_primitives::{Receipt, SealedBlockWithSenders}; -use reth_primitives_traits::SignedTransaction; -use reth_storage_api::BlockReader; +use reth_primitives_traits::{BlockBody, SignedTransaction}; +use reth_storage_api::{BlockReader, ProviderBlock}; use std::sync::Arc; /// Returns all matching of a block's receipts when the transaction hashes are known. @@ -54,20 +55,23 @@ pub enum ProviderOrBlock<'a, P: BlockReader> { /// Provider Provider(&'a P), /// [`SealedBlockWithSenders`] - Block(Arc), + Block(Arc>>), } /// Appends all matching logs of a block's receipts. /// If the log matches, look up the corresponding transaction hash. -pub fn append_matching_block_logs>( +pub fn append_matching_block_logs

( all_logs: &mut Vec, provider_or_block: ProviderOrBlock<'_, P>, filter: &FilteredParams, block_num_hash: BlockNumHash, - receipts: &[Receipt], + receipts: &[P::Receipt], removed: bool, block_timestamp: u64, -) -> Result<(), ProviderError> { +) -> Result<(), ProviderError> +where + P: BlockReader, +{ // Tracks the index of a log in the entire block. let mut log_index: u64 = 0; @@ -81,13 +85,13 @@ pub fn append_matching_block_logs // The transaction hash of the current receipt. let mut transaction_hash = None; - for log in &receipt.logs { + for log in receipt.logs() { if log_matches_filter(block_num_hash, log, filter) { // if this is the first match in the receipt's logs, look up the transaction hash if transaction_hash.is_none() { transaction_hash = match &provider_or_block { ProviderOrBlock::Block(block) => { - block.body.transactions.get(receipt_idx).map(|t| t.hash()) + block.body.transactions().get(receipt_idx).map(|t| t.trie_hash()) } ProviderOrBlock::Provider(provider) => { let first_tx_num = match loaded_first_tx_num { diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 092d94851622..0a17e5e5f2b9 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -9,7 +9,10 @@ use alloy_network::Ethereum; use alloy_primitives::U256; use derive_more::Deref; use reth_primitives::NodePrimitives; -use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; +use reth_provider::{ + BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ProviderBlock, + ProviderReceipt, +}; use reth_rpc_eth_api::{ helpers::{EthSigner, SpawnBlocking}, node::RpcNodeCoreExt, @@ -37,7 +40,7 @@ use crate::eth::EthTxBuilder; /// 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 { +pub struct EthApi { /// All nested fields bundled together. #[deref] pub(super) inner: Arc>, @@ -45,7 +48,10 @@ pub struct EthApi { pub tx_resp_builder: EthTxBuilder, } -impl Clone for EthApi { +impl Clone for EthApi +where + Provider: BlockReader, +{ fn clone(&self) -> Self { Self { inner: self.inner.clone(), tx_resp_builder: EthTxBuilder } } @@ -61,7 +67,7 @@ where provider: Provider, pool: Pool, network: Network, - eth_cache: EthStateCache, + eth_cache: EthStateCache, gas_oracle: GasPriceOracle, gas_cap: impl Into, max_simulate_blocks: u64, @@ -106,8 +112,8 @@ where Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions< Primitives: NodePrimitives< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, + Block = ProviderBlock, + Receipt = ProviderReceipt, >, >, { @@ -137,6 +143,7 @@ where impl EthApiTypes for EthApi where Self: Send + Sync, + Provider: BlockReader, { type Error = EthApiError; type NetworkTypes = Ethereum; @@ -149,7 +156,7 @@ where impl RpcNodeCore for EthApi where - Provider: Send + Sync + Clone + Unpin, + Provider: BlockReader + Send + Sync + Clone + Unpin, Pool: Send + Sync + Clone + Unpin, Network: Send + Sync + Clone, EvmConfig: Send + Sync + Clone + Unpin, @@ -184,16 +191,21 @@ where impl RpcNodeCoreExt for EthApi where - Self: RpcNodeCore, + Provider: BlockReader + Send + Sync + Clone + Unpin, + Pool: Send + Sync + Clone + Unpin, + Network: Send + Sync + Clone, + EvmConfig: Send + Sync + Clone + Unpin, { #[inline] - fn cache(&self) -> &EthStateCache { + fn cache(&self) -> &EthStateCache, ProviderReceipt> { self.inner.cache() } } impl std::fmt::Debug for EthApi +where + Provider: BlockReader, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthApi").finish_non_exhaustive() @@ -204,6 +216,7 @@ impl SpawnBlocking for EthApi where Self: Clone + Send + Sync + 'static, + Provider: BlockReader, { #[inline] fn io_task_spawner(&self) -> impl TaskSpawner { @@ -223,7 +236,7 @@ where /// Container type `EthApi` #[allow(missing_debug_implementations)] -pub struct EthApiInner { +pub struct EthApiInner { /// The transaction pool. pool: Pool, /// The provider that can interact with the chain. @@ -233,7 +246,7 @@ pub struct EthApiInner { /// All configured Signers signers: parking_lot::RwLock>>, /// The async cache frontend for eth related data - eth_cache: EthStateCache, + eth_cache: EthStateCache, /// The async gas oracle frontend for gas price suggestions gas_oracle: GasPriceOracle, /// Maximum gas limit for `eth_call` and call tracing RPC methods. @@ -269,7 +282,7 @@ where provider: Provider, pool: Pool, network: Network, - eth_cache: EthStateCache, + eth_cache: EthStateCache, gas_oracle: GasPriceOracle, gas_cap: impl Into, max_simulate_blocks: u64, @@ -312,7 +325,10 @@ where } } -impl EthApiInner { +impl EthApiInner +where + Provider: BlockReader, +{ /// Returns a handle to data on disk. #[inline] pub const fn provider(&self) -> &Provider { @@ -321,7 +337,7 @@ impl EthApiInner &EthStateCache { + pub const fn cache(&self) -> &EthStateCache { &self.eth_cache } @@ -455,8 +471,7 @@ mod tests { ) -> EthApi { let evm_config = EthEvmConfig::new(provider.chain_spec()); let cache = EthStateCache::spawn(provider.clone(), Default::default()); - let fee_history_cache = - FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); + let fee_history_cache = FeeHistoryCache::new(FeeHistoryCacheConfig::default()); let gas_cap = provider.chain_spec().max_gas_limit(); EthApi::new( diff --git a/crates/rpc/rpc/src/eth/filter.rs b/crates/rpc/rpc/src/eth/filter.rs index 6ed72b6ca746..8f50fefcb613 100644 --- a/crates/rpc/rpc/src/eth/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -9,8 +9,8 @@ use alloy_rpc_types_eth::{ use async_trait::async_trait; use jsonrpsee::{core::RpcResult, server::IdProvider}; use reth_chainspec::ChainInfo; -use reth_primitives::{Receipt, SealedBlockWithSenders}; -use reth_provider::{BlockIdReader, BlockReader, ProviderError}; +use reth_primitives::SealedBlockWithSenders; +use reth_provider::{BlockIdReader, BlockReader, ProviderBlock, ProviderError, ProviderReceipt}; use reth_rpc_eth_api::{ EthApiTypes, EthFilterApiServer, FullEthApiTypes, RpcTransaction, TransactionCompat, }; @@ -40,7 +40,7 @@ use tracing::{error, trace}; const MAX_HEADERS_RANGE: u64 = 1_000; // with ~530bytes per header this is ~500kb /// `Eth` filter RPC implementation. -pub struct EthFilter { +pub struct EthFilter { /// All nested fields bundled together inner: Arc>>, /// Assembles response data w.r.t. network. @@ -50,6 +50,7 @@ pub struct EthFilter { impl Clone for EthFilter where Eth: EthApiTypes, + Provider: BlockReader, { fn clone(&self) -> Self { Self { inner: self.inner.clone(), tx_resp_builder: self.tx_resp_builder.clone() } @@ -58,7 +59,7 @@ where impl EthFilter where - Provider: Send + Sync + 'static, + Provider: BlockReader + Send + Sync + 'static, Pool: Send + Sync + 'static, Eth: EthApiTypes + 'static, { @@ -73,7 +74,7 @@ where pub fn new( provider: Provider, pool: Pool, - eth_cache: EthStateCache, + eth_cache: EthStateCache, config: EthFilterConfig, task_spawner: Box, tx_resp_builder: Eth::TransactionCompat, @@ -334,6 +335,7 @@ where impl std::fmt::Debug for EthFilter where Eth: EthApiTypes, + Provider: BlockReader, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthFilter").finish_non_exhaustive() @@ -342,7 +344,7 @@ where /// Container type `EthFilter` #[derive(Debug)] -struct EthFilterInner { +struct EthFilterInner { /// The transaction pool. pool: Pool, /// The provider that can interact with the chain. @@ -356,7 +358,7 @@ struct EthFilterInner { /// Maximum number of logs that can be returned in a response max_logs_per_response: usize, /// The async cache frontend for eth related data - eth_cache: EthStateCache, + eth_cache: EthStateCache, /// maximum number of headers to read at once for range filter max_headers_range: u64, /// The type that can spawn tasks. @@ -536,8 +538,13 @@ where &self, block_num_hash: &BlockNumHash, best_number: u64, - ) -> Result>, Option>)>, EthFilterError> - { + ) -> Result< + Option<( + Arc>>, + Option>>>, + )>, + EthFilterError, + > { // The last 4 blocks are most likely cached, so we can just fetch them let cached_range = best_number.saturating_sub(4)..=best_number; let receipts_block = if cached_range.contains(&block_num_hash.number) { diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs index f6aae34b961e..409a3095abd8 100644 --- a/crates/rpc/rpc/src/eth/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -2,10 +2,10 @@ use alloy_rpc_types_eth::{BlockId, TransactionReceipt}; use reth_primitives::TransactionMeta; -use reth_provider::{BlockReaderIdExt, HeaderProvider}; +use reth_provider::{BlockReader, HeaderProvider}; use reth_rpc_eth_api::{ helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, - RpcReceipt, + RpcNodeCoreExt, RpcReceipt, }; use reth_rpc_eth_types::{EthApiError, EthReceiptBuilder}; @@ -18,6 +18,7 @@ where NetworkTypes: alloy_network::Network, Provider: HeaderProvider, >, + Provider: BlockReader, { async fn block_receipts( &self, @@ -62,7 +63,7 @@ where impl LoadBlock for EthApi where - Self: LoadPendingBlock + SpawnBlocking, - Provider: BlockReaderIdExt, + Self: LoadPendingBlock + SpawnBlocking + RpcNodeCoreExt, + Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/eth/helpers/call.rs b/crates/rpc/rpc/src/eth/helpers/call.rs index c0594c023fa1..3835503a4c88 100644 --- a/crates/rpc/rpc/src/eth/helpers/call.rs +++ b/crates/rpc/rpc/src/eth/helpers/call.rs @@ -3,12 +3,15 @@ use crate::EthApi; use alloy_consensus::Header; use reth_evm::ConfigureEvm; +use reth_provider::BlockReader; use reth_rpc_eth_api::helpers::{ estimate::EstimateCall, Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking, }; -impl EthCall for EthApi where - Self: EstimateCall + LoadPendingBlock +impl EthCall for EthApi +where + Self: EstimateCall + LoadPendingBlock, + Provider: BlockReader, { } @@ -16,6 +19,7 @@ impl Call for EthApi> + SpawnBlocking, EvmConfig: ConfigureEvm

, + Provider: BlockReader, { #[inline] fn call_gas_limit(&self) -> u64 { @@ -28,7 +32,9 @@ where } } -impl EstimateCall for EthApi where - Self: Call +impl EstimateCall for EthApi +where + Self: Call, + Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/eth/helpers/fees.rs b/crates/rpc/rpc/src/eth/helpers/fees.rs index e1a17ef647c5..045d6dcb545a 100644 --- a/crates/rpc/rpc/src/eth/helpers/fees.rs +++ b/crates/rpc/rpc/src/eth/helpers/fees.rs @@ -1,14 +1,18 @@ //! Contains RPC handler implementations for fee history. use reth_chainspec::{EthChainSpec, EthereumHardforks}; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; +use reth_provider::{ + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, +}; use reth_rpc_eth_api::helpers::{EthFees, LoadBlock, LoadFee}; use reth_rpc_eth_types::{FeeHistoryCache, GasPriceOracle}; use crate::EthApi; -impl EthFees for EthApi where - Self: LoadFee +impl EthFees for EthApi +where + Self: LoadFee, + Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/eth/helpers/pending_block.rs b/crates/rpc/rpc/src/eth/helpers/pending_block.rs index afd69a2f4041..8d8d15d2e466 100644 --- a/crates/rpc/rpc/src/eth/helpers/pending_block.rs +++ b/crates/rpc/rpc/src/eth/helpers/pending_block.rs @@ -4,7 +4,8 @@ use alloy_consensus::Header; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_evm::ConfigureEvm; use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderTx, StateProviderFactory, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderTx, + StateProviderFactory, }; use reth_rpc_eth_api::{ helpers::{LoadPendingBlock, SpawnBlocking}, @@ -33,6 +34,7 @@ where >, Evm: ConfigureEvm
>, >, + Provider: BlockReader, { #[inline] fn pending_block(&self) -> &tokio::sync::Mutex> { diff --git a/crates/rpc/rpc/src/eth/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs index ae723fc5314f..12fbf0957345 100644 --- a/crates/rpc/rpc/src/eth/helpers/receipt.rs +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -1,7 +1,7 @@ //! Builds an RPC receipt response w.r.t. data layout of network. use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; -use reth_provider::{ReceiptProvider, TransactionsProvider}; +use reth_provider::{BlockReader, ReceiptProvider, TransactionsProvider}; use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcNodeCoreExt, RpcReceipt}; use reth_rpc_eth_types::{EthApiError, EthReceiptBuilder}; @@ -13,6 +13,7 @@ where Provider: TransactionsProvider + ReceiptProvider, >, + Provider: BlockReader, { async fn build_transaction_receipt( &self, diff --git a/crates/rpc/rpc/src/eth/helpers/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs index 32645ba08d6c..022c3153b017 100644 --- a/crates/rpc/rpc/src/eth/helpers/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -11,11 +11,14 @@ use alloy_rpc_types_eth::TransactionRequest; use alloy_signer::SignerSync; use alloy_signer_local::PrivateKeySigner; use reth_primitives::TransactionSigned; +use reth_provider::BlockReader; use reth_rpc_eth_api::helpers::{signer::Result, AddDevSigners, EthSigner}; use reth_rpc_eth_types::SignError; impl AddDevSigners for EthApi +where + Provider: BlockReader, { fn with_dev_accounts(&self) { *self.inner.signers().write() = DevSigner::random_signers(20) diff --git a/crates/rpc/rpc/src/eth/helpers/spec.rs b/crates/rpc/rpc/src/eth/helpers/spec.rs index a44692e18a35..f7bc89ae2b17 100644 --- a/crates/rpc/rpc/src/eth/helpers/spec.rs +++ b/crates/rpc/rpc/src/eth/helpers/spec.rs @@ -1,7 +1,7 @@ use alloy_primitives::U256; use reth_chainspec::EthereumHardforks; use reth_network_api::NetworkInfo; -use reth_provider::{BlockNumReader, ChainSpecProvider, StageCheckpointReader}; +use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider, StageCheckpointReader}; use reth_rpc_eth_api::{helpers::EthApiSpec, RpcNodeCore}; use crate::EthApi; @@ -14,6 +14,7 @@ where + StageCheckpointReader, Network: NetworkInfo, >, + Provider: BlockReader, { fn starting_block(&self) -> U256 { self.inner.starting_block() diff --git a/crates/rpc/rpc/src/eth/helpers/state.rs b/crates/rpc/rpc/src/eth/helpers/state.rs index 1b9c5bffd219..99d2856ad832 100644 --- a/crates/rpc/rpc/src/eth/helpers/state.rs +++ b/crates/rpc/rpc/src/eth/helpers/state.rs @@ -1,12 +1,12 @@ //! Contains RPC handler implementations specific to state. use reth_chainspec::EthereumHardforks; -use reth_provider::{ChainSpecProvider, StateProviderFactory}; +use reth_provider::{BlockReader, ChainSpecProvider, StateProviderFactory}; use reth_transaction_pool::TransactionPool; use reth_rpc_eth_api::{ helpers::{EthState, LoadState, SpawnBlocking}, - RpcNodeCore, + RpcNodeCoreExt, }; use crate::EthApi; @@ -14,17 +14,22 @@ use crate::EthApi; impl EthState for EthApi where Self: LoadState + SpawnBlocking, + Provider: BlockReader, { fn max_proof_window(&self) -> u64 { self.inner.eth_proof_window() } } -impl LoadState for EthApi where - Self: RpcNodeCore< - Provider: StateProviderFactory + ChainSpecProvider, +impl LoadState for EthApi +where + Self: RpcNodeCoreExt< + Provider: BlockReader + + StateProviderFactory + + ChainSpecProvider, Pool: TransactionPool, - > + >, + Provider: BlockReader, { } @@ -58,12 +63,12 @@ mod tests { pool, NoopNetwork::default(), cache.clone(), - GasPriceOracle::new(NoopProvider::default(), Default::default(), cache.clone()), + GasPriceOracle::new(NoopProvider::default(), Default::default(), cache), ETHEREUM_BLOCK_GAS_LIMIT, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_ETH_PROOF_WINDOW, BlockingTaskPool::build().expect("failed to build tracing pool"), - FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), + FeeHistoryCache::new(FeeHistoryCacheConfig::default()), evm_config, DEFAULT_PROOF_PERMITS, ) @@ -84,12 +89,12 @@ mod tests { pool, (), cache.clone(), - GasPriceOracle::new(mock_provider, Default::default(), cache.clone()), + GasPriceOracle::new(mock_provider, Default::default(), cache), ETHEREUM_BLOCK_GAS_LIMIT, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_ETH_PROOF_WINDOW + 1, BlockingTaskPool::build().expect("failed to build tracing pool"), - FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), + FeeHistoryCache::new(FeeHistoryCacheConfig::default()), evm_config, DEFAULT_PROOF_PERMITS, ) diff --git a/crates/rpc/rpc/src/eth/helpers/trace.rs b/crates/rpc/rpc/src/eth/helpers/trace.rs index 9c60a4c105f9..ed7150153e55 100644 --- a/crates/rpc/rpc/src/eth/helpers/trace.rs +++ b/crates/rpc/rpc/src/eth/helpers/trace.rs @@ -7,7 +7,9 @@ use reth_rpc_eth_api::helpers::{LoadState, Trace}; use crate::EthApi; -impl Trace for EthApi where - Self: LoadState> +impl Trace for EthApi +where + Self: LoadState>, + Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/eth/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs index 7f2ca4f772a8..647e16c25af6 100644 --- a/crates/rpc/rpc/src/eth/helpers/transaction.rs +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -1,9 +1,9 @@ //! Contains RPC handler implementations specific to transactions -use reth_provider::{BlockReaderIdExt, TransactionsProvider}; +use reth_provider::{BlockReader, BlockReaderIdExt, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, - FullEthApiTypes, RpcNodeCore, + FullEthApiTypes, RpcNodeCoreExt, }; use reth_transaction_pool::TransactionPool; @@ -13,6 +13,7 @@ impl EthTransactions for EthApi where Self: LoadTransaction, + Provider: BlockReader, { #[inline] fn signers(&self) -> &parking_lot::RwLock>> { @@ -25,7 +26,8 @@ impl LoadTransaction where Self: SpawnBlocking + FullEthApiTypes - + RpcNodeCore, + + RpcNodeCoreExt, + Provider: BlockReader, { } @@ -58,8 +60,7 @@ mod tests { let evm_config = EthEvmConfig::new(noop_provider.chain_spec()); let cache = EthStateCache::spawn(noop_provider, Default::default()); - let fee_history_cache = - FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); + let fee_history_cache = FeeHistoryCache::new(FeeHistoryCacheConfig::default()); let eth_api = EthApi::new( noop_provider, pool.clone(), diff --git a/crates/storage/storage-api/src/block.rs b/crates/storage/storage-api/src/block.rs index 917796038e9d..43a86aaf750e 100644 --- a/crates/storage/storage-api/src/block.rs +++ b/crates/storage/storage-api/src/block.rs @@ -40,6 +40,9 @@ impl BlockSource { } } +/// A helper type alias to access [`BlockReader::Block`]. +pub type ProviderBlock

=

::Block; + /// Api trait for fetching `Block` related data. /// /// If not requested otherwise, implementers of this trait should prioritize fetching blocks from diff --git a/crates/storage/storage-api/src/receipts.rs b/crates/storage/storage-api/src/receipts.rs index 67257cce67ce..fdb703238564 100644 --- a/crates/storage/storage-api/src/receipts.rs +++ b/crates/storage/storage-api/src/receipts.rs @@ -1,14 +1,18 @@ use crate::BlockIdReader; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag}; use alloy_primitives::{TxHash, TxNumber}; +use reth_primitives_traits::Receipt; use reth_storage_errors::provider::ProviderResult; use std::ops::RangeBounds; +/// A helper type alias to access [`ReceiptProvider::Receipt`]. +pub type ProviderReceipt

=

::Receipt; + /// Client trait for fetching receipt data. #[auto_impl::auto_impl(&, Arc)] pub trait ReceiptProvider: Send + Sync { /// The receipt type. - type Receipt: Send + Sync; + type Receipt: Receipt; /// Get receipt by transaction number /// diff --git a/crates/storage/storage-api/src/transactions.rs b/crates/storage/storage-api/src/transactions.rs index 3bb20b7e161a..ca2bcaeb4690 100644 --- a/crates/storage/storage-api/src/transactions.rs +++ b/crates/storage/storage-api/src/transactions.rs @@ -1,4 +1,4 @@ -use crate::{BlockNumReader, BlockReader, ReceiptProvider}; +use crate::{BlockNumReader, BlockReader}; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{Address, BlockNumber, TxHash, TxNumber}; use reth_primitives::TransactionMeta; @@ -84,9 +84,6 @@ pub trait TransactionsProvider: BlockNumReader + Send + Sync { /// A helper type alias to access [`TransactionsProvider::Transaction`]. pub type ProviderTx

=

::Transaction; -/// A helper type alias to access [`ReceiptProvider::Receipt`]. -pub type ProviderReceipt

=

::Receipt; - /// Client trait for fetching additional transactions related data. #[auto_impl::auto_impl(&, Arc)] pub trait TransactionsProviderExt: BlockReader + Send + Sync {