diff --git a/Cargo.lock b/Cargo.lock index 91ca9dbbc1c..1c10ac524fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,7 +165,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.6.13", + "winnow 0.6.10", ] [[package]] @@ -621,7 +621,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa2fbd22d353d8685bd9fee11ba2d8b5c3b1d11e56adb3265fcf1f32bfdf404" dependencies = [ - "winnow 0.6.13", + "winnow 0.6.10", ] [[package]] @@ -757,9 +757,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] @@ -1650,9 +1650,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", @@ -1788,9 +1788,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "coins-bip32" @@ -3079,7 +3079,7 @@ dependencies = [ [[package]] name = "foundry-blob-explorers" version = "0.1.0" -source = "git+https://github.com/foundry-rs/block-explorers#d5fdf79cd62f378448907663fc4ba9d085393b35" +source = "git+https://github.com/foundry-rs/block-explorers#1674a68b073a3637c16f2d3f9700cf6332ffe4a6" dependencies = [ "alloy-chains", "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -7544,9 +7544,11 @@ dependencies = [ "reth-rpc", "reth-rpc-api", "reth-rpc-types", + "reth-tasks", "reth-transaction-pool", "revm", "thiserror", + "tokio", ] [[package]] @@ -8453,9 +8455,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.5" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7699249cc2c7d71939f30868f47e9d7add0bdc030d90ee10bfd16887ff8bb1c8" +checksum = "b26f4c25a604fcb3a1bcd96dd6ba37c93840de95de8198d94c0d571a74a804d1" dependencies = [ "bytemuck", "byteorder", @@ -9321,9 +9323,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -9363,9 +9365,9 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "12.9.2" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71297dc3e250f7dbdf8adb99e235da783d690f5819fdeb4cce39d9cfb0aca9f1" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" dependencies = [ "debugid", "memmap2 0.9.4", @@ -9375,9 +9377,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.9.2" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424fa2c9bf2c862891b9cfd354a752751a6730fd838a4691e7f6c2c7957b9daf" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -9831,7 +9833,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.13", + "winnow 0.6.10", ] [[package]] @@ -10203,9 +10205,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "universal-hash" @@ -10273,9 +10275,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" @@ -10461,9 +10463,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" dependencies = [ "rustls-pki-types", ] @@ -10582,9 +10584,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" dependencies = [ "windows-targets 0.52.5", ] @@ -10739,9 +10741,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "f217b6745021054125ef5741032a021a9c65f82bee2a8017cca928f1e3179991" dependencies = [ "memchr", ] diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 48f9f709ce8..d05c1a50a96 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -23,9 +23,11 @@ reth-rpc-types.workspace = true reth-primitives = { workspace = true, features = ["optimism"] } reth-provider.workspace = true reth-transaction-pool.workspace = true +reth-tasks.workspace = true # async futures.workspace = true +tokio = { workspace = true, features = ["sync"] } # rpc jsonrpsee.workspace = true diff --git a/crates/optimism/rpc/src/block.rs b/crates/optimism/rpc/src/block.rs index 079255d6985..53b23233d83 100644 --- a/crates/optimism/rpc/src/block.rs +++ b/crates/optimism/rpc/src/block.rs @@ -1,13 +1,21 @@ //! Loads and formats OP block RPC response. +use reth_evm::ConfigureEvm; use reth_primitives::TransactionMeta; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider}; +use reth_provider::{ + BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory, +}; use reth_rpc::eth::{ - api::{BuildReceipt, EthBlocks, LoadBlock, ReceiptBuilder}, + api::{ + EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, PendingBlock, ReceiptBuilder, + SpawnBlocking, + }, cache::EthStateCache, error::EthResult, }; use reth_rpc_types::{AnyTransactionReceipt, BlockId}; +use reth_transaction_pool::TransactionPool; +use tokio::sync::Mutex; use crate::receipt::op_receipt_fields; @@ -16,14 +24,19 @@ use super::OptimismApi; impl EthBlocks for OptimismApi where - Provider: BlockReaderIdExt + ChainSpecProvider, + Self: LoadBlock, + Provider: BlockReaderIdExt + ChainSpecProvider + HeaderProvider, { + fn provider(&self) -> impl HeaderProvider { + self.inner.provider() + } + async fn block_receipts( &self, block_id: BlockId, ) -> EthResult>> where - Self: BuildReceipt, + Self: LoadReceipt, { if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? { let block_number = block.number; @@ -69,6 +82,7 @@ where impl LoadBlock for OptimismApi where + Self: LoadPendingBlock + SpawnBlocking, Provider: BlockReaderIdExt, { #[inline] @@ -81,3 +95,33 @@ where self.inner.cache() } } + +impl LoadPendingBlock + for OptimismApi +where + Provider: BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory, + Pool: TransactionPool, + EvmConfig: ConfigureEvm, +{ + #[inline] + fn provider( + &self, + ) -> impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory { + self.inner.provider() + } + + #[inline] + fn pool(&self) -> impl TransactionPool { + self.inner.pool() + } + + #[inline] + fn pending_block(&self) -> &Mutex> { + self.inner.pending_block() + } + + #[inline] + fn evm_config(&self) -> &impl ConfigureEvm { + self.inner.evm_config() + } +} diff --git a/crates/optimism/rpc/src/lib.rs b/crates/optimism/rpc/src/lib.rs index 6ee47316419..c968f7b2f0b 100644 --- a/crates/optimism/rpc/src/lib.rs +++ b/crates/optimism/rpc/src/lib.rs @@ -9,7 +9,8 @@ use std::sync::Arc; -use reth_rpc::eth::api::EthApiInner; +use reth_rpc::eth::api::{EthApiInner, SpawnBlocking}; +use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; pub mod block; pub mod error; @@ -22,16 +23,22 @@ pub mod transaction; /// requests. See [`EthApi`](reth_rpc::EthApi) for the default L1 implementation. #[allow(missing_debug_implementations)] #[allow(dead_code)] +#[derive(Clone)] pub struct OptimismApi { /// All nested fields bundled together. inner: Arc>, } -unsafe impl Send - for OptimismApi -{ -} -unsafe impl Sync +impl SpawnBlocking for OptimismApi +where + Self: Clone + Send + Sync + 'static, { + fn io_task_spawner(&self) -> impl TaskSpawner { + self.inner.task_spawner() + } + + fn tracing_task_pool(&self) -> &BlockingTaskPool { + self.inner.blocking_task_pool() + } } diff --git a/crates/optimism/rpc/src/receipt.rs b/crates/optimism/rpc/src/receipt.rs index da26ebe90d3..e9735d86b03 100644 --- a/crates/optimism/rpc/src/receipt.rs +++ b/crates/optimism/rpc/src/receipt.rs @@ -4,15 +4,16 @@ use crate::{transaction::OptimismTxMeta, OptimismApi}; use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; use reth_provider::{BlockIdReader, ChainSpecProvider}; use reth_rpc::eth::{ - api::{BuildReceipt, ReceiptBuilder}, + api::{LoadReceipt, ReceiptBuilder}, cache::EthStateCache, error::{EthApiError, EthResult}, }; use reth_rpc_types::{AnyTransactionReceipt, OptimismTransactionReceiptFields}; -impl BuildReceipt +impl LoadReceipt for OptimismApi where + Self: Send + Sync, Provider: BlockIdReader + ChainSpecProvider, { #[inline] @@ -25,10 +26,7 @@ where tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> EthResult - where - Self: Send + Sync, - { + ) -> EthResult { let (block, receipts) = self .cache() .get_block_and_receipts(meta.block_hash) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index b797d40f339..186adecbd17 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -33,7 +33,7 @@ use tokio::sync::{AcquireError, OwnedSemaphorePermit}; use crate::{ eth::{ - api::{LoadBlock, LoadTransaction, StateCacheDB, TraceExt}, + api::{EthTransactions, LoadBlock, LoadTransaction, StateCacheDB, TraceExt}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, }, @@ -639,7 +639,7 @@ where + StateProviderFactory + EvmEnvProvider + 'static, - Eth: EthApiSpec + LoadBlock + TraceExt + 'static, + Eth: EthApiSpec + EthTransactions + LoadBlock + TraceExt + 'static, { /// Handler for `debug_getRawHeader` async fn raw_header(&self, block_id: BlockId) -> RpcResult { diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs index da718f6be0d..776379b1445 100644 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ b/crates/rpc/rpc/src/eth/api/block.rs @@ -1,30 +1,31 @@ //! Contains RPC handler implementations specific to blocks. -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::BlockId; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; -use reth_rpc_types::{Header, Index, RichBlock}; -use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; -use reth_transaction_pool::TransactionPool; +use reth_provider::{BlockReaderIdExt, HeaderProvider}; use crate::{ eth::{ - api::{EthBlocks, LoadBlock, LoadPendingBlock}, + api::{EthBlocks, LoadBlock}, cache::EthStateCache, - error::{EthApiError, EthResult}, }, EthApi, }; -impl EthBlocks for EthApi where - Self: LoadBlock +use super::{LoadPendingBlock, SpawnBlocking}; + +impl EthBlocks for EthApi +where + Self: LoadBlock, + Provider: HeaderProvider, { + #[inline] + fn provider(&self) -> impl HeaderProvider { + self.inner.provider() + } } impl LoadBlock for EthApi where - Self: Send + Sync, + Self: LoadPendingBlock + SpawnBlocking, Provider: BlockReaderIdExt, { #[inline] @@ -37,104 +38,3 @@ where self.inner.cache() } } - -impl EthApi -where - Self: LoadBlock, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Returns the uncle headers of the given block - /// - /// Returns an empty vec if there are none. - pub(crate) fn ommers( - &self, - block_id: impl Into, - ) -> EthResult>> { - let block_id = block_id.into(); - Ok(self.provider().ommers_by_id(block_id)?) - } - - pub(crate) async fn ommer_by_block_and_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - let block_id = block_id.into(); - - let uncles = if block_id.is_pending() { - // Pending block can be fetched directly without need for caching - self.provider().pending_block()?.map(|block| block.ommers) - } else { - self.provider().ommers_by_id(block_id)? - } - .unwrap_or_default(); - - let index = usize::from(index); - let uncle = - uncles.into_iter().nth(index).map(|header| uncle_block_from_header(header).into()); - Ok(uncle) - } - - /// Returns the number transactions in the given block. - /// - /// Returns `None` if the block does not exist - pub(crate) async fn block_transaction_count( - &self, - block_id: impl Into, - ) -> EthResult> { - let block_id = block_id.into(); - - if block_id.is_pending() { - // Pending block can be fetched directly without need for caching - return Ok(self.provider().pending_block()?.map(|block| block.body.len())) - } - - let block_hash = match self.provider().block_hash_for_id(block_id)? { - Some(block_hash) => block_hash, - None => return Ok(None), - }; - - Ok(self.cache().get_block_transactions(block_hash).await?.map(|txs| txs.len())) - } - - /// Returns the populated rpc block object for the given block id. - /// - /// If `full` is true, the block object will contain all transaction objects, otherwise it will - /// only contain the transaction hashes. - pub(crate) async fn rpc_block( - &self, - block_id: impl Into + Send, - full: bool, - ) -> EthResult> - where - Self: LoadPendingBlock, - { - let block = match self.block_with_senders(block_id).await? { - Some(block) => block, - None => return Ok(None), - }; - let block_hash = block.hash(); - let total_difficulty = self - .provider() - .header_td_by_number(block.number)? - .ok_or(EthApiError::UnknownBlockNumber)?; - let block = from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))?; - Ok(Some(block.into())) - } - - /// Returns the block header for the given block id. - pub(crate) async fn rpc_block_header( - &self, - block_id: impl Into + Send, - ) -> EthResult> - where - Self: LoadPendingBlock, - { - let header = self.rpc_block(block_id, false).await?.map(|block| block.inner.header); - Ok(header) - } -} diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 6b169b15747..e3e0cb74e94 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -3,12 +3,18 @@ use reth_evm::ConfigureEvm; use crate::eth::{ - api::{Call, EthCall}, + api::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking}, EthApi, }; +impl EthCall for EthApi where + Self: Call + LoadPendingBlock +{ +} + impl Call for EthApi where + Self: LoadState + SpawnBlocking, EvmConfig: ConfigureEvm, { #[inline] @@ -21,8 +27,3 @@ where self.inner.evm_config() } } - -impl EthCall for EthApi where - Self: Call -{ -} diff --git a/crates/rpc/rpc/src/eth/api/fee_history.rs b/crates/rpc/rpc/src/eth/api/fee_history.rs index da43be5510a..4b03bec9d81 100644 --- a/crates/rpc/rpc/src/eth/api/fee_history.rs +++ b/crates/rpc/rpc/src/eth/api/fee_history.rs @@ -1,6 +1,11 @@ //! Consist of types adjacent to the fee history cache and its configs -use crate::eth::{cache::EthStateCache, error::EthApiError}; +use std::{ + collections::{BTreeMap, VecDeque}, + fmt::Debug, + sync::{atomic::Ordering::SeqCst, Arc}, +}; + use futures::{ future::{Fuse, FusedFuture}, FutureExt, Stream, StreamExt, @@ -15,13 +20,10 @@ use reth_provider::{BlockReaderIdExt, CanonStateNotification, ChainSpecProvider} use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY; use reth_rpc_types::TxGasAndReward; use serde::{Deserialize, Serialize}; -use std::{ - collections::{BTreeMap, VecDeque}, - fmt::Debug, - sync::{atomic::Ordering::SeqCst, Arc}, -}; use tracing::trace; +use crate::eth::{cache::EthStateCache, error::EthApiError}; + /// Contains cached fee history entries for blocks. /// /// Purpose for this is to provide cached data for `eth_feeHistory`. diff --git a/crates/rpc/rpc/src/eth/api/fees.rs b/crates/rpc/rpc/src/eth/api/fees.rs index fe79cf027d6..88c1b39d63e 100644 --- a/crates/rpc/rpc/src/eth/api/fees.rs +++ b/crates/rpc/rpc/src/eth/api/fees.rs @@ -4,7 +4,7 @@ use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderPr use crate::{ eth::{ - api::{EthFees, LoadFee}, + api::{EthFees, LoadBlock, LoadFee}, cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, @@ -19,7 +19,7 @@ impl EthFees for EthApi LoadFee for EthApi where - Self: Send + Sync, + Self: LoadBlock, Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider, { #[inline] diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 01c8ed5f16b..985b0069541 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -35,9 +35,9 @@ pub mod transactions; pub use pending_block::PendingBlock; pub use receipt::ReceiptBuilder; pub use traits::{ - BuildReceipt, Call, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadBlock, - LoadBlockExt, LoadFee, LoadPendingBlock, LoadState, LoadStateExt, LoadTransaction, - RawTransactionForwarder, SpawnBlocking, StateCacheDB, Trace, TraceExt, + Call, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadBlock, LoadFee, + LoadPendingBlock, LoadReceipt, LoadState, LoadTransaction, RawTransactionForwarder, + SpawnBlocking, StateCacheDB, Trace, TraceExt, }; pub use transactions::TransactionSource; @@ -46,7 +46,7 @@ pub use transactions::TransactionSource; /// Defines core functionality of the `eth` API implementation. #[async_trait] #[auto_impl::auto_impl(&, Arc)] -pub trait EthApiSpec: EthTransactions + Send + Sync { +pub trait EthApiSpec: Send + Sync { /// Returns the current ethereum protocol version. async fn protocol_version(&self) -> RethResult; @@ -272,7 +272,7 @@ where impl SpawnBlocking for EthApi where - Self: Send + Sync + 'static, + Self: Clone + Send + Sync + 'static, { fn io_task_spawner(&self) -> impl TaskSpawner { self.inner.task_spawner() diff --git a/crates/rpc/rpc/src/eth/api/receipt.rs b/crates/rpc/rpc/src/eth/api/receipt.rs index 4ea20b0ca4d..27cea387080 100644 --- a/crates/rpc/rpc/src/eth/api/receipt.rs +++ b/crates/rpc/rpc/src/eth/api/receipt.rs @@ -10,7 +10,24 @@ use reth_rpc_types::{ TransactionReceipt, WithOtherFields, }; -use crate::eth::error::{EthApiError, EthResult}; +use crate::{ + eth::{ + api::LoadReceipt, + cache::EthStateCache, + error::{EthApiError, EthResult}, + }, + EthApi, +}; + +impl LoadReceipt for EthApi +where + Self: Send + Sync, +{ + #[inline] + fn cache(&self) -> &EthStateCache { + &self.inner.eth_cache + } +} /// Receipt response builder. #[derive(Debug)] diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 87f1e31707a..1d3820e9e28 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -20,9 +20,7 @@ use tracing::trace; use crate::{ eth::{ - api::{ - BuildReceipt, EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, Trace, - }, + api::{EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions}, error::EthApiError, revm_utils::EvmOverrides, EthApi, @@ -33,14 +31,7 @@ use crate::{ #[async_trait::async_trait] impl EthApiServer for EthApi where - Self: EthApiSpec - + EthTransactions - + EthBlocks - + EthState - + EthCall - + EthFees - + Trace - + BuildReceipt, + Self: EthApiSpec + EthTransactions + EthBlocks + EthState + EthCall + EthFees, Pool: TransactionPool + 'static, Provider: BlockReaderIdExt + ChainSpecProvider @@ -91,7 +82,7 @@ where /// Handler for: `eth_getBlockByHash` async fn block_by_hash(&self, hash: B256, full: bool) -> Result> { trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash"); - Ok(Self::rpc_block(self, hash, full).await?) + Ok(EthBlocks::rpc_block(self, hash, full).await?) } /// Handler for: `eth_getBlockByNumber` @@ -101,13 +92,13 @@ where full: bool, ) -> Result> { trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber"); - Ok(Self::rpc_block(self, number, full).await?) + Ok(EthBlocks::rpc_block(self, number, full).await?) } /// Handler for: `eth_getBlockTransactionCountByHash` async fn block_transaction_count_by_hash(&self, hash: B256) -> Result> { trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash"); - Ok(Self::block_transaction_count(self, hash).await?.map(U256::from)) + Ok(EthBlocks::block_transaction_count(self, hash).await?.map(U256::from)) } /// Handler for: `eth_getBlockTransactionCountByNumber` @@ -116,19 +107,19 @@ where number: BlockNumberOrTag, ) -> Result> { trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber"); - Ok(Self::block_transaction_count(self, number).await?.map(U256::from)) + Ok(EthBlocks::block_transaction_count(self, number).await?.map(U256::from)) } /// Handler for: `eth_getUncleCountByBlockHash` async fn block_uncles_count_by_hash(&self, hash: B256) -> Result> { trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash"); - Ok(Self::ommers(self, hash)?.map(|ommers| U256::from(ommers.len()))) + Ok(EthBlocks::ommers(self, hash)?.map(|ommers| U256::from(ommers.len()))) } /// Handler for: `eth_getUncleCountByBlockNumber` async fn block_uncles_count_by_number(&self, number: BlockNumberOrTag) -> Result> { trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber"); - Ok(Self::ommers(self, number)?.map(|ommers| U256::from(ommers.len()))) + Ok(EthBlocks::ommers(self, number)?.map(|ommers| U256::from(ommers.len()))) } /// Handler for: `eth_getBlockReceipts` @@ -147,7 +138,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex"); - Ok(Self::ommer_by_block_and_index(self, hash, index).await?) + Ok(EthBlocks::ommer_by_block_and_index(self, hash, index).await?) } /// Handler for: `eth_getUncleByBlockNumberAndIndex` @@ -157,7 +148,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex"); - Ok(Self::ommer_by_block_and_index(self, number, index).await?) + Ok(EthBlocks::ommer_by_block_and_index(self, number, index).await?) } /// Handler for: `eth_getRawTransactionByHash` @@ -179,7 +170,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex"); - Ok(Self::raw_transaction_by_block_and_tx_index(self, hash, index).await?) + Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash, index).await?) } /// Handler for: `eth_getTransactionByBlockHashAndIndex` @@ -189,7 +180,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex"); - Ok(Self::transaction_by_block_and_tx_index(self, hash, index).await?) + Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash, index).await?) } /// Handler for: `eth_getRawTransactionByBlockNumberAndIndex` @@ -199,7 +190,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex"); - Ok(Self::raw_transaction_by_block_and_tx_index(self, number, index).await?) + Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number, index).await?) } /// Handler for: `eth_getTransactionByBlockNumberAndIndex` @@ -209,7 +200,7 @@ where index: Index, ) -> Result> { trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex"); - Ok(Self::transaction_by_block_and_tx_index(self, number, index).await?) + Ok(EthTransactions::transaction_by_block_and_tx_index(self, number, index).await?) } /// Handler for: `eth_getTransactionReceipt` @@ -255,13 +246,13 @@ where /// Handler for: `eth_getHeaderByNumber` async fn header_by_number(&self, block_number: BlockNumberOrTag) -> Result> { trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); - Ok(Self::rpc_block_header(self, block_number).await?) + Ok(EthBlocks::rpc_block_header(self, block_number).await?) } /// Handler for: `eth_getHeaderByHash` async fn header_by_hash(&self, hash: B256) -> Result> { trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash"); - Ok(Self::rpc_block_header(self, hash).await?) + Ok(EthBlocks::rpc_block_header(self, hash).await?) } /// Handler for: `eth_call` @@ -402,7 +393,7 @@ where /// Handler for: `eth_sign` async fn sign(&self, address: Address, message: Bytes) -> Result { trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign"); - Ok(Self::sign(self, address, message).await?) + Ok(EthTransactions::sign(self, address, message).await?) } /// Handler for: `eth_signTransaction` @@ -413,7 +404,7 @@ where /// Handler for: `eth_signTypedData` async fn sign_typed_data(&self, address: Address, data: Value) -> Result { trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData"); - Ok(Self::sign_typed_data(self, data, address)?) + Ok(EthTransactions::sign_typed_data(self, data, address)?) } /// Handler for: `eth_getProof` diff --git a/crates/rpc/rpc/src/eth/api/sign.rs b/crates/rpc/rpc/src/eth/api/sign.rs index 5cbdefa41c9..b6c096084ef 100644 --- a/crates/rpc/rpc/src/eth/api/sign.rs +++ b/crates/rpc/rpc/src/eth/api/sign.rs @@ -1,45 +1,8 @@ //! Contains RPC handler implementations specific to sign endpoints -use crate::{ - eth::{ - error::{EthResult, SignError}, - signer::{DevSigner, EthSigner}, - }, - EthApi, -}; -use alloy_dyn_abi::TypedData; -use reth_primitives::{Address, Bytes}; -use serde_json::Value; +use crate::{eth::signer::DevSigner, EthApi}; impl EthApi { - pub(crate) async fn sign(&self, account: Address, message: Bytes) -> EthResult { - Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes()) - } - - pub(crate) fn sign_typed_data(&self, data: Value, account: Address) -> EthResult { - Ok(self - .find_signer(&account)? - .sign_typed_data( - account, - &serde_json::from_value::(data) - .map_err(|_| SignError::InvalidTypedData)?, - )? - .to_hex_bytes()) - } - - pub(crate) fn find_signer( - &self, - account: &Address, - ) -> Result, SignError> { - self.inner - .signers - .read() - .iter() - .find(|signer| signer.is_signer_for(account)) - .map(|signer| dyn_clone::clone_box(&**signer)) - .ok_or(SignError::NoAccount) - } - /// Generates 20 random developer accounts. /// Used in DEV mode. pub fn with_dev_accounts(&self) { diff --git a/crates/rpc/rpc/src/eth/api/trace.rs b/crates/rpc/rpc/src/eth/api/trace.rs index 253818c6072..9f336223eea 100644 --- a/crates/rpc/rpc/src/eth/api/trace.rs +++ b/crates/rpc/rpc/src/eth/api/trace.rs @@ -2,10 +2,14 @@ use reth_evm::ConfigureEvm; -use crate::{eth::api::Trace, EthApi}; +use crate::{ + eth::api::{LoadState, Trace}, + EthApi, +}; impl Trace for EthApi where + Self: LoadState, EvmConfig: ConfigureEvm, { #[inline] diff --git a/crates/rpc/rpc/src/eth/api/traits/block.rs b/crates/rpc/rpc/src/eth/api/traits/block.rs index 3f4c838a57f..2526353e555 100644 --- a/crates/rpc/rpc/src/eth/api/traits/block.rs +++ b/crates/rpc/rpc/src/eth/api/traits/block.rs @@ -4,18 +4,86 @@ use std::sync::Arc; use futures::Future; use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta}; -use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt}; -use reth_rpc_types::AnyTransactionReceipt; +use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider}; +use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock}; +use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; use crate::eth::{ - api::{BuildReceipt, LoadPendingBlock, ReceiptBuilder, SpawnBlocking}, + api::{LoadPendingBlock, LoadReceipt, ReceiptBuilder, SpawnBlocking}, cache::EthStateCache, - error::EthResult, + error::{EthApiError, EthResult}, }; /// Block related functions for the [`EthApiServer`](reth_rpc_api::EthApiServer) trait in the /// `eth_` namespace. pub trait EthBlocks: LoadBlock { + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl HeaderProvider; + + /// Returns the block header for the given block id. + fn rpc_block_header( + &self, + block_id: impl Into + Send, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { Ok(self.rpc_block(block_id, false).await?.map(|block| block.inner.header)) } + } + + /// Returns the populated rpc block object for the given block id. + /// + /// If `full` is true, the block object will contain all transaction objects, otherwise it will + /// only contain the transaction hashes. + fn rpc_block( + &self, + block_id: impl Into + Send, + full: bool, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { + let block = match self.block_with_senders(block_id).await? { + Some(block) => block, + None => return Ok(None), + }; + let block_hash = block.hash(); + let total_difficulty = EthBlocks::provider(self) + .header_td_by_number(block.number)? + .ok_or(EthApiError::UnknownBlockNumber)?; + let block = + from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))?; + Ok(Some(block.into())) + } + } + + /// Returns the number transactions in the given block. + /// + /// Returns `None` if the block does not exist + fn block_transaction_count( + &self, + block_id: impl Into, + ) -> impl Future>> + Send { + let block_id = block_id.into(); + + async move { + if block_id.is_pending() { + // Pending block can be fetched directly without need for caching + return Ok(LoadBlock::provider(self).pending_block()?.map(|block| block.body.len())) + } + + let block_hash = match LoadBlock::provider(self).block_hash_for_id(block_id)? { + Some(block_hash) => block_hash, + None => return Ok(None), + }; + + Ok(self.cache().get_block_transactions(block_hash).await?.map(|txs| txs.len())) + } + } + /// Helper function for `eth_getBlockReceipts`. /// /// Returns all transaction receipts in block, or `None` if block wasn't found. @@ -24,7 +92,7 @@ pub trait EthBlocks: LoadBlock { block_id: BlockId, ) -> impl Future>>> + Send where - Self: BuildReceipt, + Self: LoadReceipt, { async move { if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? { @@ -61,10 +129,72 @@ pub trait EthBlocks: LoadBlock { Ok(None) } } + + /// Helper method that loads a bock and all its receipts. + fn load_block_and_receipts( + &self, + block_id: BlockId, + ) -> impl Future>)>>> + Send + where + Self: LoadReceipt, + { + async move { + if block_id.is_pending() { + return Ok(LoadBlock::provider(self) + .pending_block_and_receipts()? + .map(|(sb, receipts)| (sb, Arc::new(receipts)))) + } + + if let Some(block_hash) = LoadBlock::provider(self).block_hash_for_id(block_id)? { + return Ok(LoadReceipt::cache(self).get_block_and_receipts(block_hash).await?) + } + + Ok(None) + } + } + + /// Returns uncle headers of given block. + /// + /// Returns an empty vec if there are none. + fn ommers( + &self, + block_id: impl Into, + ) -> EthResult>> { + let block_id = block_id.into(); + Ok(LoadBlock::provider(self).ommers_by_id(block_id)?) + } + + /// Returns uncle block at given index in given block. + /// + /// Returns `None` if index out of range. + fn ommer_by_block_and_index( + &self, + block_id: impl Into, + index: Index, + ) -> impl Future>> + Send { + let block_id = block_id.into(); + + async move { + let uncles = if block_id.is_pending() { + // Pending block can be fetched directly without need for caching + LoadBlock::provider(self).pending_block()?.map(|block| block.ommers) + } else { + LoadBlock::provider(self).ommers_by_id(block_id)? + } + .unwrap_or_default(); + + let index = usize::from(index); + let uncle = + uncles.into_iter().nth(index).map(|header| uncle_block_from_header(header).into()); + Ok(uncle) + } + } } /// Loads a block from database. -pub trait LoadBlock: Send + Sync { +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. +pub trait LoadBlock: LoadPendingBlock + SpawnBlocking { // Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. @@ -79,10 +209,7 @@ pub trait LoadBlock: Send + Sync { fn block( &self, block_id: impl Into + Send, - ) -> impl Future>> + Send - where - Self: LoadPendingBlock + SpawnBlocking, - { + ) -> impl Future>> + Send { async move { self.block_with_senders(block_id) .await @@ -94,10 +221,7 @@ pub trait LoadBlock: Send + Sync { fn block_with_senders( &self, block_id: impl Into + Send, - ) -> impl Future>> + Send - where - Self: LoadPendingBlock + SpawnBlocking, - { + ) -> impl Future>> + Send { async move { let block_id = block_id.into(); @@ -120,28 +244,4 @@ pub trait LoadBlock: Send + Sync { Ok(self.cache().get_sealed_block_with_senders(block_hash).await?) } } - - /// Helper method that loads a bock and all its receipts. - fn load_block_and_receipts( - &self, - block_id: BlockId, - ) -> impl Future>)>>> + Send - where - Self: BuildReceipt, - { - async move { - if block_id.is_pending() { - return Ok(self - .provider() - .pending_block_and_receipts()? - .map(|(sb, receipts)| (sb, Arc::new(receipts)))) - } - - if let Some(block_hash) = self.provider().block_hash_for_id(block_id)? { - return Ok(BuildReceipt::cache(self).get_block_and_receipts(block_hash).await?) - } - - Ok(None) - } - } } diff --git a/crates/rpc/rpc/src/eth/api/traits/call.rs b/crates/rpc/rpc/src/eth/api/traits/call.rs index ef7f26fa287..25e7be6219f 100644 --- a/crates/rpc/rpc/src/eth/api/traits/call.rs +++ b/crates/rpc/rpc/src/eth/api/traits/call.rs @@ -19,7 +19,7 @@ use revm_primitives::{ use tracing::trace; use crate::eth::{ - api::{LoadBlock, LoadState, LoadStateExt, LoadTransaction, SpawnBlocking, Trace}, + api::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace}, error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError}, revm_utils::{ apply_state_overrides, build_call_evm_env, caller_gas_allowance, @@ -40,17 +40,14 @@ pub type StateCacheDB<'a> = CacheDB, - ) -> impl Future> + Send - where - Self: LoadStateExt, - { + ) -> impl Future> + Send { Call::estimate_gas_at(self, request, at, state_override) } @@ -60,10 +57,7 @@ pub trait EthCall: Call { request: TransactionRequest, block_number: Option, overrides: EvmOverrides, - ) -> impl Future> + Send - where - Self: LoadStateExt, - { + ) -> impl Future> + Send { async move { let (res, _env) = self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?; @@ -81,7 +75,7 @@ pub trait EthCall: Call { mut state_override: Option, ) -> impl Future>> + Send where - Self: LoadStateExt + LoadBlock, + Self: LoadBlock, { async move { let Bundle { transactions, block_override } = bundle; @@ -188,7 +182,7 @@ pub trait EthCall: Call { block_number: Option, ) -> impl Future> + Send where - Self: LoadStateExt + Trace, + Self: Trace, { async move { let block_id = block_number.unwrap_or_default(); @@ -211,7 +205,7 @@ pub trait EthCall: Call { mut request: TransactionRequest, ) -> EthResult where - Self: LoadState + Trace, + Self: Trace, { let state = self.state_at_block_id(at)?; @@ -274,7 +268,7 @@ pub trait EthCall: Call { } /// Executes code on state. -pub trait Call { +pub trait Call: LoadState + SpawnBlocking { /// Returns default gas limit to use for `eth_call` and tracing RPC methods. /// /// Data access in default trait method implementations. @@ -283,7 +277,6 @@ pub trait Call { /// Executes the closure with the state that corresponds to the given [`BlockId`]. fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult where - Self: LoadState, F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult, { let state = self.state_at_block_id(at)?; @@ -320,7 +313,7 @@ pub trait Call { overrides: EvmOverrides, ) -> impl Future> + Send where - Self: LoadStateExt, + Self: LoadPendingBlock, { let this = self.clone(); self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env)) @@ -333,7 +326,6 @@ pub trait Call { f: F, ) -> impl Future> + Send where - Self: LoadState + SpawnBlocking, F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult + Send + 'static, T: Send + 'static, { @@ -356,7 +348,7 @@ pub trait Call { f: F, ) -> impl Future> + Send where - Self: LoadStateExt, + Self: LoadPendingBlock, F: FnOnce(StateCacheDBRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> EthResult + Send + 'static, @@ -401,7 +393,7 @@ pub trait Call { f: F, ) -> impl Future>> + Send where - Self: LoadStateExt + LoadTransaction + LoadBlock, + Self: LoadBlock + LoadPendingBlock + LoadTransaction, F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB<'_>) -> EthResult + Send + 'static, @@ -491,7 +483,7 @@ pub trait Call { state_override: Option, ) -> impl Future> + Send where - Self: LoadStateExt, + Self: LoadPendingBlock, { async move { let (cfg, block_env, at) = self.evm_env_at(at).await?; diff --git a/crates/rpc/rpc/src/eth/api/traits/fee.rs b/crates/rpc/rpc/src/eth/api/traits/fee.rs index e9a4b5225ee..fa7f45c2982 100644 --- a/crates/rpc/rpc/src/eth/api/traits/fee.rs +++ b/crates/rpc/rpc/src/eth/api/traits/fee.rs @@ -9,7 +9,7 @@ use tracing::debug; use crate::eth::{ api::{ fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry}, - LoadBlockExt, + LoadBlock, }, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError}, @@ -25,7 +25,7 @@ pub trait EthFees: LoadFee { /// See also: fn gas_price(&self) -> impl Future> + Send where - Self: LoadBlockExt, + Self: LoadBlock, { LoadFee::gas_price(self) } @@ -33,7 +33,7 @@ pub trait EthFees: LoadFee { /// Returns a suggestion for a base fee for blob transactions. fn blob_base_fee(&self) -> impl Future> + Send where - Self: LoadBlockExt, + Self: LoadBlock, { LoadFee::blob_base_fee(self) } @@ -77,7 +77,9 @@ pub trait EthFees: LoadFee { block_count = max_fee_history } - let Some(end_block) = self.provider().block_number_for_id(newest_block.into())? else { + let Some(end_block) = + LoadFee::provider(self).block_number_for_id(newest_block.into())? + else { return Err(EthApiError::UnknownBlockNumber) }; @@ -141,12 +143,13 @@ pub trait EthFees: LoadFee { // Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the // next block base_fee_per_gas - .push(last_entry.next_block_base_fee(&self.provider().chain_spec()) as u128); + .push(last_entry.next_block_base_fee(&LoadFee::provider(self).chain_spec()) + as u128); base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default()); } else { // read the requested header range - let headers = self.provider().sealed_headers_range(start_block..=end_block)?; + let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block)?; if headers.len() != block_count as usize { return Err(EthApiError::InvalidBlockRange) } @@ -162,8 +165,7 @@ pub trait EthFees: LoadFee { // Percentiles were specified, so we need to collect reward percentile ino if let Some(percentiles) = &reward_percentiles { - let (transactions, receipts) = self - .cache() + let (transactions, receipts) = LoadFee::cache(self) .get_transactions_and_receipts(header.hash()) .await? .ok_or(EthApiError::InvalidBlockRange)?; @@ -187,7 +189,7 @@ pub trait EthFees: LoadFee { // The unwrap is safe since we checked earlier that we got at least 1 header. let last_header = headers.last().expect("is present"); base_fee_per_gas.push( - self.provider().chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee( + LoadFee::provider(self).chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee( last_header.gas_used as u128, last_header.gas_limit as u128, last_header.base_fee_per_gas.unwrap_or_default() as u128, @@ -226,7 +228,9 @@ pub trait EthFees: LoadFee { } /// Loads fee from database. -pub trait LoadFee: Send + Sync + Clone { +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` fees RPC methods. +pub trait LoadFee: LoadBlock { // Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. @@ -252,10 +256,7 @@ pub trait LoadFee: Send + Sync + Clone { fn legacy_gas_price( &self, gas_price: Option, - ) -> impl Future> + Send - where - Self: LoadBlockExt, - { + ) -> impl Future> + Send { async move { match gas_price { Some(gas_price) => Ok(gas_price), @@ -275,10 +276,7 @@ pub trait LoadFee: Send + Sync + Clone { &self, max_fee_per_gas: Option, max_priority_fee_per_gas: Option, - ) -> impl Future> + Send - where - Self: LoadBlockExt, - { + ) -> impl Future> + Send { async move { let max_fee_per_gas = match max_fee_per_gas { Some(max_fee_per_gas) => max_fee_per_gas, @@ -310,10 +308,7 @@ pub trait LoadFee: Send + Sync + Clone { fn eip4844_blob_fee( &self, blob_fee: Option, - ) -> impl Future> + Send - where - Self: LoadBlockExt, - { + ) -> impl Future> + Send { async move { match blob_fee { Some(blob_fee) => Ok(blob_fee), @@ -325,10 +320,7 @@ pub trait LoadFee: Send + Sync + Clone { /// Returns a suggestion for a gas price for legacy transactions. /// /// See also: - fn gas_price(&self) -> impl Future> + Send - where - Self: LoadBlockExt, - { + fn gas_price(&self) -> impl Future> + Send { let header = self.block(BlockNumberOrTag::Latest); let suggested_tip = self.suggested_priority_fee(); async move { @@ -339,10 +331,7 @@ pub trait LoadFee: Send + Sync + Clone { } /// Returns a suggestion for a base fee for blob transactions. - fn blob_base_fee(&self) -> impl Future> + Send - where - Self: LoadBlockExt, - { + fn blob_base_fee(&self) -> impl Future> + Send { async move { self.block(BlockNumberOrTag::Latest) .await? diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index aaa84daa9e5..38b518f6e38 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -29,22 +29,12 @@ pub use blocking_task::SpawnBlocking; pub use call::{Call, EthCall, StateCacheDB}; pub use fee::{EthFees, LoadFee}; pub use pending_block::LoadPendingBlock; -pub use receipt::BuildReceipt; +pub use receipt::LoadReceipt; pub use state::{EthState, LoadState}; pub use trace::Trace; pub use transaction::{EthTransactions, LoadTransaction, RawTransactionForwarder}; -/// Extension trait that bundles traits needed for loading execution environment. -pub trait LoadStateExt: LoadState + LoadPendingBlock + SpawnBlocking {} - -impl LoadStateExt for T where T: LoadState + LoadPendingBlock + SpawnBlocking {} - -/// Extension trait that bundles traits needed for loading a block at any point in finalization. -pub trait LoadBlockExt: LoadBlock + LoadPendingBlock + SpawnBlocking {} - -impl LoadBlockExt for T where T: LoadBlock + LoadPendingBlock + SpawnBlocking {} - /// Extension trait that bundles traits needed for tracing transactions. -pub trait TraceExt: LoadStateExt + Trace + Call {} +pub trait TraceExt: LoadPendingBlock + SpawnBlocking + Trace + Call {} -impl TraceExt for T where T: LoadStateExt + Trace + Call {} +impl TraceExt for T where T: LoadPendingBlock + Trace + Call {} diff --git a/crates/rpc/rpc/src/eth/api/traits/pending_block.rs b/crates/rpc/rpc/src/eth/api/traits/pending_block.rs index 482b8d0bf14..8ab068e1a9d 100644 --- a/crates/rpc/rpc/src/eth/api/traits/pending_block.rs +++ b/crates/rpc/rpc/src/eth/api/traits/pending_block.rs @@ -23,6 +23,8 @@ use crate::eth::{ }; /// Loads a pending block from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. #[auto_impl::auto_impl(&, Arc)] pub trait LoadPendingBlock { /// Returns a handle for reading data from disk. diff --git a/crates/rpc/rpc/src/eth/api/traits/receipt.rs b/crates/rpc/rpc/src/eth/api/traits/receipt.rs index 4ebc5e757a3..e8fabee0d86 100644 --- a/crates/rpc/rpc/src/eth/api/traits/receipt.rs +++ b/crates/rpc/rpc/src/eth/api/traits/receipt.rs @@ -12,8 +12,10 @@ use crate::eth::{ }; /// Assembles transaction receipt data w.r.t to network. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods. #[auto_impl::auto_impl(&, Arc)] -pub trait BuildReceipt { +pub trait LoadReceipt: Send + Sync { /// Returns a handle for reading data from memory. /// /// Data access in default (L1) trait method implementations. @@ -25,10 +27,7 @@ pub trait BuildReceipt { tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> impl Future> + Send - where - Self: Send + Sync, - { + ) -> impl Future> + Send { async move { // get all receipts for the block let all_receipts = match self.cache().get_receipts(meta.block_hash).await? { diff --git a/crates/rpc/rpc/src/eth/api/traits/state.rs b/crates/rpc/rpc/src/eth/api/traits/state.rs index ebe4bd5e8b5..c0637396707 100644 --- a/crates/rpc/rpc/src/eth/api/traits/state.rs +++ b/crates/rpc/rpc/src/eth/api/traits/state.rs @@ -14,7 +14,7 @@ use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId}; use crate::{ eth::{ - api::{pending_block::PendingBlockEnv, LoadPendingBlock, LoadStateExt, SpawnBlocking}, + api::{pending_block::PendingBlockEnv, LoadPendingBlock, SpawnBlocking}, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError}, }, @@ -119,6 +119,8 @@ pub trait EthState: LoadState + SpawnBlocking { } /// Loads state from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` state RPC methods. pub trait LoadState { /// Returns a handle for reading state from database. /// @@ -204,7 +206,7 @@ pub trait LoadState { header: &Header, ) -> impl Future> + Send where - Self: LoadStateExt, + Self: LoadPendingBlock + SpawnBlocking, { async move { // get the parent config first diff --git a/crates/rpc/rpc/src/eth/api/traits/trace.rs b/crates/rpc/rpc/src/eth/api/traits/trace.rs index 144de8a6c37..39d54d9abde 100644 --- a/crates/rpc/rpc/src/eth/api/traits/trace.rs +++ b/crates/rpc/rpc/src/eth/api/traits/trace.rs @@ -10,14 +10,15 @@ use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use revm_primitives::{EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState}; use crate::eth::{ - api::{Call, LoadBlock, LoadState, LoadStateExt, LoadTransaction, StateCacheDB}, + api::{ + traits::call::{StateCacheDBRefMutWrapper, StateProviderTraitObjWrapper}, + Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, StateCacheDB, + }, error::{EthApiError, EthResult}, }; -use super::call::{StateCacheDBRefMutWrapper, StateProviderTraitObjWrapper}; - /// Executes CPU heavy tasks. -pub trait Trace { +pub trait Trace: LoadState { /// Returns a handle for reading evm config. /// /// Data access in default (L1) trait method implementations. @@ -76,7 +77,7 @@ pub trait Trace { f: F, ) -> EthResult where - Self: LoadState + Call, + Self: Call, F: FnOnce(TracingInspector, ResultAndState) -> EthResult, { self.with_state_at_block(at, |state| { @@ -102,7 +103,7 @@ pub trait Trace { f: F, ) -> impl Future> + Send where - Self: LoadStateExt + Call, + Self: LoadPendingBlock + Call, F: FnOnce(TracingInspector, ResultAndState, StateCacheDB<'_>) -> EthResult + Send + 'static, @@ -133,7 +134,7 @@ pub trait Trace { f: F, ) -> impl Future>> + Send where - Self: LoadStateExt + LoadTransaction + Call, + Self: LoadPendingBlock + LoadTransaction + Call, F: FnOnce( TransactionInfo, TracingInspector, @@ -163,7 +164,7 @@ pub trait Trace { f: F, ) -> impl Future>> + Send where - Self: LoadStateExt + LoadTransaction + Call, + Self: LoadPendingBlock + LoadTransaction + Call, F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB<'_>) -> EthResult + Send + 'static, @@ -222,7 +223,7 @@ pub trait Trace { f: F, ) -> impl Future>>> + Send where - Self: LoadStateExt + LoadBlock, + Self: LoadBlock, F: Fn( TransactionInfo, TracingInspector, @@ -260,7 +261,7 @@ pub trait Trace { f: F, ) -> impl Future>>> + Send where - Self: LoadStateExt + LoadBlock, + Self: LoadBlock, F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDB<'_>) -> EthResult + Send + 'static, @@ -360,7 +361,7 @@ pub trait Trace { f: F, ) -> impl Future>>> + Send where - Self: LoadStateExt + LoadBlock, + Self: LoadBlock, // This is the callback that's invoked for each transaction with the inspector, the result, // state and db F: Fn( @@ -398,7 +399,7 @@ pub trait Trace { f: F, ) -> impl Future>>> + Send where - Self: LoadStateExt + LoadBlock, + Self: LoadBlock, // This is the callback that's invoked for each transaction with the inspector, the result, // state and db F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDB<'_>) -> EthResult diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index bcb9af709d9..b8f33a346dc 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -3,6 +3,7 @@ use std::{fmt, sync::Arc}; +use alloy_dyn_abi::TypedData; use futures::Future; use reth_primitives::{ Address, BlockId, Bytes, FromRecoveredPooledTransaction, IntoRecoveredTransaction, Receipt, @@ -14,12 +15,13 @@ use reth_rpc_types::{ EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest, LegacyTransactionRequest, }, - AnyTransactionReceipt, TransactionRequest, TypedTransactionRequest, + AnyTransactionReceipt, Index, Transaction, TransactionRequest, TypedTransactionRequest, }; +use reth_rpc_types_compat::transaction::from_recovered_with_block_context; use reth_transaction_pool::{TransactionOrigin, TransactionPool}; use crate::eth::{ - api::{BuildReceipt, EthApiSpec, LoadBlock, LoadFee, LoadStateExt, SpawnBlocking}, + api::{Call, EthApiSpec, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, SpawnBlocking}, cache::EthStateCache, error::{EthApiError, EthResult, SignError}, signer::EthSigner, @@ -27,8 +29,6 @@ use crate::eth::{ TransactionSource, }; -use super::Call; - /// Transaction related functions for the [`EthApiServer`](reth_rpc_api::EthApiServer) trait in /// the `eth_` namespace. /// @@ -52,7 +52,7 @@ use super::Call; /// See also /// /// This implementation follows the behaviour of Geth and disables the basefee check for tracing. -pub trait EthTransactions: LoadTransaction + Send + Sync { +pub trait EthTransactions: LoadTransaction { /// Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. @@ -76,10 +76,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { fn transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send - where - Self: SpawnBlocking, - { + ) -> impl Future>> + Send { LoadTransaction::transaction_by_hash(self, hash) } @@ -103,10 +100,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { fn raw_transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send - where - Self: SpawnBlocking, - { + ) -> impl Future>> + Send { async move { // Note: this is mostly used to fetch pooled transactions so we check the pool first if let Some(tx) = @@ -128,10 +122,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { fn historical_transaction_by_hash_at( &self, hash: B256, - ) -> impl Future>> + Send - where - Self: SpawnBlocking, - { + ) -> impl Future>> + Send { async move { match self.transaction_by_hash_at(hash).await? { None => Ok(None), @@ -149,7 +140,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { hash: B256, ) -> impl Future>> + Send where - Self: BuildReceipt + SpawnBlocking + 'static, + Self: LoadReceipt + 'static, { async move { let result = self.load_transaction_and_receipt(hash).await?; @@ -169,7 +160,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { hash: TxHash, ) -> impl Future>> + Send where - Self: SpawnBlocking + 'static, + Self: 'static, { let this = self.clone(); self.spawn_blocking_io(move |_| { @@ -188,6 +179,59 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { }) } + /// Get [`Transaction`] by [`BlockId`] and index of transaction within that block. + /// + /// Returns `Ok(None)` if the block does not exist, or index is out of range. + fn transaction_by_block_and_tx_index( + &self, + block_id: impl Into + Send, + index: Index, + ) -> impl Future>> + Send + where + Self: LoadBlock, + { + async move { + if let Some(block) = self.block_with_senders(block_id.into()).await? { + let block_hash = block.hash(); + let block_number = block.number; + let base_fee_per_gas = block.base_fee_per_gas; + if let Some(tx) = block.into_transactions_ecrecovered().nth(index.into()) { + return Ok(Some(from_recovered_with_block_context( + tx, + block_hash, + block_number, + base_fee_per_gas, + index.into(), + ))) + } + } + + Ok(None) + } + } + + /// Get transaction, as raw bytes, by [`BlockId`] and index of transaction within that block. + /// + /// Returns `Ok(None)` if the block does not exist, or index is out of range. + fn raw_transaction_by_block_and_tx_index( + &self, + block_id: impl Into + Send, + index: Index, + ) -> impl Future>> + Send + where + Self: LoadBlock, + { + async move { + if let Some(block) = self.block_with_senders(block_id.into()).await? { + if let Some(tx) = block.transactions().nth(index.into()) { + return Ok(Some(tx.envelope_encoded())) + } + } + + Ok(None) + } + } + /// Decodes and recovers the transaction and submits it to the pool. /// /// Returns the hash of the transaction. @@ -221,7 +265,7 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { mut request: TransactionRequest, ) -> impl Future> + Send where - Self: EthApiSpec + LoadStateExt + LoadBlock + LoadFee + Call, + Self: EthApiSpec + LoadBlock + LoadPendingBlock + LoadFee + Call, { async move { let from = match request.from { @@ -438,10 +482,44 @@ pub trait EthTransactions: LoadTransaction + Send + Sync { } Err(EthApiError::InvalidTransactionSignature) } + + /// Signs given message. Returns the signature. + fn sign( + &self, + account: Address, + message: Bytes, + ) -> impl Future> + Send { + async move { Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes()) } + } + + /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. + fn sign_typed_data(&self, data: serde_json::Value, account: Address) -> EthResult { + Ok(self + .find_signer(&account)? + .sign_typed_data( + account, + &serde_json::from_value::(data) + .map_err(|_| SignError::InvalidTypedData)?, + )? + .to_hex_bytes()) + } + + /// Returns the signer for the given account, if found in configured signers. + fn find_signer(&self, account: &Address) -> Result, SignError> { + self.signers() + .read() + .iter() + .find(|signer| signer.is_signer_for(account)) + .map(|signer| dyn_clone::clone_box(&**signer)) + .ok_or(SignError::NoAccount) + } } /// Loads a transaction from database. -pub trait LoadTransaction { +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` transactions RPC +/// methods. +pub trait LoadTransaction: SpawnBlocking { /// Transaction pool with pending transactions. [`TransactionPool::Transaction`] is the /// supported transaction type. type Pool: TransactionPool; @@ -469,10 +547,7 @@ pub trait LoadTransaction { fn transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send - where - Self: SpawnBlocking, - { + ) -> impl Future>> + Send { async move { // Try to find the transaction on disk let mut resp = self @@ -519,10 +594,7 @@ pub trait LoadTransaction { fn transaction_by_hash_at( &self, transaction_hash: B256, - ) -> impl Future>> + Send - where - Self: SpawnBlocking, - { + ) -> impl Future>> + Send { async move { match self.transaction_by_hash(transaction_hash).await? { None => Ok(None), @@ -558,8 +630,6 @@ pub trait LoadTransaction { &self, hash: B256, ) -> impl Future>> + Send - where - Self: SpawnBlocking, { async move { let (transaction, at) = match self.transaction_by_hash_at(hash).await? { diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index f18caaefc53..f848eb7a489 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -2,55 +2,26 @@ use std::sync::Arc; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{BlockId, Bytes, TransactionSignedEcRecovered, B256}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, TransactionsProvider, -}; -use reth_rpc_types::{Index, Transaction, TransactionInfo}; +use reth_primitives::{TransactionSignedEcRecovered, B256}; +use reth_provider::{BlockReaderIdExt, TransactionsProvider}; +use reth_rpc_types::{Transaction, TransactionInfo}; use reth_rpc_types_compat::transaction::from_recovered_with_block_context; use reth_transaction_pool::TransactionPool; use crate::{ eth::{ - api::{BuildReceipt, EthTransactions, LoadBlock, LoadTransaction, RawTransactionForwarder}, + api::{EthTransactions, LoadTransaction, RawTransactionForwarder, SpawnBlocking}, cache::EthStateCache, - error::EthResult, revm_utils::FillableTransaction, signer::EthSigner, }, EthApi, }; -impl LoadTransaction - for EthApi -where - Provider: TransactionsProvider, - Pool: TransactionPool, -{ - type Pool = Pool; - - #[inline] - fn provider(&self) -> impl TransactionsProvider { - self.inner.provider() - } - - #[inline] - fn cache(&self) -> &EthStateCache { - self.inner.cache() - } - - #[inline] - fn pool(&self) -> &Self::Pool { - self.inner.pool() - } -} - impl EthTransactions for EthApi where - Self: LoadTransaction + Send + Sync, + Self: LoadTransaction, Pool: TransactionPool + 'static, Provider: BlockReaderIdExt, { @@ -70,64 +41,28 @@ where } } -impl BuildReceipt +impl LoadTransaction for EthApi -{ - #[inline] - fn cache(&self) -> &EthStateCache { - &self.inner.eth_cache - } -} - -// === impl EthApi === - -impl EthApi where - Self: LoadBlock, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + 'static, - Network: NetworkInfo + 'static, - EvmConfig: ConfigureEvm, + Self: SpawnBlocking, + Provider: TransactionsProvider, + Pool: TransactionPool, { - /// Get Transaction by [`BlockId`] and the index of the transaction within that Block. - /// - /// Returns `Ok(None)` if the block does not exist, or the block as fewer transactions - pub(crate) async fn transaction_by_block_and_tx_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - if let Some(block) = self.block_with_senders(block_id.into()).await? { - let block_hash = block.hash(); - let block_number = block.number; - let base_fee_per_gas = block.base_fee_per_gas; - if let Some(tx) = block.into_transactions_ecrecovered().nth(index.into()) { - return Ok(Some(from_recovered_with_block_context( - tx, - block_hash, - block_number, - base_fee_per_gas, - index.into(), - ))) - } - } + type Pool = Pool; - Ok(None) + #[inline] + fn provider(&self) -> impl TransactionsProvider { + self.inner.provider() } - pub(crate) async fn raw_transaction_by_block_and_tx_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - if let Some(block) = self.block_with_senders(block_id.into()).await? { - if let Some(tx) = block.transactions().nth(index.into()) { - return Ok(Some(tx.envelope_encoded())) - } - } + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } - Ok(None) + #[inline] + fn pool(&self) -> &Self::Pool { + self.inner.pool() } } @@ -228,7 +163,7 @@ mod tests { }; use reth_evm_ethereum::EthEvmConfig; use reth_network_api::noop::NoopNetwork; - use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex}; + use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex, Bytes}; use reth_provider::test_utils::NoopProvider; use reth_tasks::pool::BlockingTaskPool; use reth_transaction_pool::test_utils::testing_pool; diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 185b22bd993..4aeea3a067b 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -20,7 +20,7 @@ use revm::{ use revm_primitives::{EnvWithHandlerCfg, MAX_BLOB_GAS_PER_BLOCK}; use crate::eth::{ - api::{Call, EthTransactions, LoadStateExt}, + api::{Call, EthTransactions, LoadPendingBlock}, error::{EthApiError, EthResult, RpcInvalidTransactionError}, revm_utils::FillableTransaction, utils::recover_raw_transaction, @@ -41,7 +41,7 @@ impl EthBundle { impl EthBundle where - Eth: EthTransactions + LoadStateExt + Call + 'static, + Eth: EthTransactions + LoadPendingBlock + Call + 'static, { /// Simulates a bundle of transactions at the top of a given block number with the state of /// another (or the same) block. This can be used to simulate future blocks with the current