From cab888f7ab66a940e99a321c0f56bc171cd8ee91 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 11:55:41 +0200 Subject: [PATCH 01/33] Make on_blocking_task method accessible in default trait method impls --- crates/optimism/rpc/src/transaction.rs | 2 +- crates/rpc/rpc/src/eth/api/call.rs | 2 +- crates/rpc/rpc/src/eth/api/mod.rs | 69 +++++++++---------- crates/rpc/rpc/src/eth/api/server.rs | 2 +- .../rpc/src/eth/api/traits/blocking_task.rs | 39 +++++++++++ crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 + crates/rpc/rpc/src/eth/api/transactions.rs | 2 +- 7 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 crates/rpc/rpc/src/eth/api/traits/blocking_task.rs diff --git a/crates/optimism/rpc/src/transaction.rs b/crates/optimism/rpc/src/transaction.rs index 2be3addbbf77..32b2efcd96ed 100644 --- a/crates/optimism/rpc/src/transaction.rs +++ b/crates/optimism/rpc/src/transaction.rs @@ -21,7 +21,7 @@ pub struct OptimismTxMeta { impl OptimismTxMeta { /// Creates a new [OptimismTxMeta]. - pub fn new( + pub const fn new( l1_block_info: Option, l1_fee: Option, l1_data_gas: Option, diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index c9f4ffb44e7b..6bf14f3aa115 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -2,7 +2,7 @@ use crate::{ eth::{ - api::EthTransactions, + api::{CallBlocking, EthTransactions}, error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError}, revm_utils::{ apply_state_overrides, build_call_evm_env, caller_gas_allowance, diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 825586928f54..f5d3375f6108 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -1,16 +1,8 @@ //! The entire implementation of the namespace is quite large, hence it is divided across several //! files. -use crate::eth::{ - api::{ - fee_history::FeeHistoryCache, - pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}, - }, - cache::EthStateCache, - error::{EthApiError, EthResult}, - gas_oracle::GasPriceOracle, - signer::EthSigner, -}; +use std::pin::Pin; + use async_trait::async_trait; use reth_errors::{RethError, RethResult}; use reth_evm::ConfigureEvm; @@ -33,7 +25,19 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use tokio::sync::{oneshot, Mutex}; +use tokio::sync::Mutex; +use traits::CallBlocking; + +use crate::eth::{ + api::{ + fee_history::FeeHistoryCache, + pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}, + }, + cache::EthStateCache, + error::{EthApiError, EthResult}, + gas_oracle::GasPriceOracle, + signer::EthSigner, +}; pub mod block; mod call; @@ -166,28 +170,6 @@ where Self { inner: Arc::new(inner) } } - /// Executes the future on a new blocking task. - /// - /// This accepts a closure that creates a new future using a clone of this type and spawns the - /// future onto a new task that is allowed to block. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations. - pub(crate) async fn on_blocking_task(&self, c: C) -> EthResult - where - C: FnOnce(Self) -> F, - F: Future> + Send + 'static, - R: Send + 'static, - { - let (tx, rx) = oneshot::channel(); - let this = self.clone(); - let f = c(this); - self.inner.task_spawner.spawn_blocking(Box::pin(async move { - let res = f.await; - let _ = tx.send(res); - })); - rx.await.map_err(|_| EthApiError::InternalEthError)? - } - /// Returns the state cache frontend pub fn cache(&self) -> &EthStateCache { &self.inner.eth_cache @@ -434,6 +416,17 @@ where } } +impl CallBlocking + for EthApi +{ + fn spawn_blocking(&self, f: Pin>) + where + F: Future + Send + 'static, + { + _ = self.inner.task_spawner().spawn_blocking(f); + } +} + /// The default gas limit for eth_call and adjacent calls. /// /// This is different from the default to regular 30M block gas limit @@ -499,13 +492,19 @@ pub struct EthApiInner { impl EthApiInner { /// Returns a handle to data on disk. #[inline] - pub fn provider(&self) -> &Provider { + pub const fn provider(&self) -> &Provider { &self.provider } /// Returns a handle to data in memory. #[inline] - pub fn cache(&self) -> &EthStateCache { + pub const fn cache(&self) -> &EthStateCache { &self.eth_cache } + + /// Returns a handle to the task spawner. + #[inline] + pub const fn task_spawner(&self) -> &dyn TaskSpawner { + &*self.task_spawner + } } diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 46b5f0b77c87..15a602e6c487 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -20,7 +20,7 @@ use tracing::trace; use crate::{ eth::{ - api::{EthBlocks, EthTransactions}, + api::{CallBlocking, EthBlocks, EthTransactions}, error::EthApiError, revm_utils::EvmOverrides, EthApi, diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs new file mode 100644 index 000000000000..461d5bbda811 --- /dev/null +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -0,0 +1,39 @@ +//! Spawns a blocking task. Should be used for long-lived database reads. + +use std::pin::Pin; + +use futures::Future; +use tokio::sync::oneshot; + +use crate::eth::error::{EthApiError, EthResult}; + +/// Calls a blocking task on a new blocking thread. +pub trait CallBlocking { + /// Spawns a blocking task. + fn spawn_blocking(&self, f: Pin>) + where + F: Future + Send + 'static; + /// Executes the future on a new blocking task. + /// + /// This accepts a closure that creates a new future using a clone of this type and spawns the + /// future onto a new task that is allowed to block. + /// + /// Note: This is expected for futures that are dominated by blocking IO operations. + fn on_blocking_task(&self, c: C) -> impl Future> + where + Self: Clone + Send + 'static, + C: FnOnce(Self) -> F, + F: Future> + Send + 'static, + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + let this = self.clone(); + let f = c(this); + self.spawn_blocking(Box::pin(async move { + let res = f.await; + let _ = tx.send(res); + })); + + async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } + } +} diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index f8fa8fccb43a..9c4c97c94856 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -1,9 +1,11 @@ //! Database access. pub mod block; +pub mod blocking_task; pub mod receipt; pub mod transaction; pub use block::EthBlocks; +pub use blocking_task::CallBlocking; pub use receipt::BuildReceipt; pub use transaction::{EthTransactions, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index e548ae9fa44e..a561f4f510dc 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -1,7 +1,7 @@ //! Contains RPC handler implementations specific to transactions use crate::{ eth::{ - api::pending_block::PendingBlockEnv, + api::{pending_block::PendingBlockEnv, CallBlocking}, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, revm_utils::{prepare_call_env, EvmOverrides}, From b902f351cbeca855f6ec03d9545830e4769394dc Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 14:46:22 +0200 Subject: [PATCH 02/33] Minimise thread interface eth api --- crates/rpc/rpc/src/eth/api/call.rs | 19 ++++++---- crates/rpc/rpc/src/eth/api/mod.rs | 35 +++++++++++------ crates/rpc/rpc/src/eth/api/server.rs | 18 ++++----- .../rpc/src/eth/api/traits/blocking_task.rs | 34 ++++------------- .../rpc/rpc/src/eth/api/traits/transaction.rs | 18 --------- crates/rpc/rpc/src/eth/api/transactions.rs | 38 ++----------------- crates/rpc/rpc/src/reth.rs | 2 +- 7 files changed, 54 insertions(+), 110 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 6bf14f3aa115..05af642841de 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -58,11 +58,11 @@ where ) -> EthResult { let (cfg, block_env, at) = self.evm_env_at(at).await?; - self.on_blocking_task(|this| async move { + self.on_blocking_task(|this| Box::pin(async move { let state = this.state_at(at)?; this.estimate_gas_with(cfg, block_env, request, state, state_override) - }) - .await + })) + .await? } /// Executes the call request (`eth_call`) and returns the output @@ -373,19 +373,22 @@ where request: TransactionRequest, block_number: Option, ) -> EthResult { + let block_id = block_number.unwrap_or_default(); + let (cfg, block, at) = self.evm_env_at(block_id).await?; + self.on_blocking_task(|this| async move { - this.create_access_list_with(request, block_number).await + this.create_access_list_with(cfg, block, at, request).await }) - .await + .await? } async fn create_access_list_with( &self, + cfg: CfgEnvWithHandlerCfg, + block: BlockEnv, + at: BlockId, mut request: TransactionRequest, - at: Option, ) -> EthResult { - let block_id = at.unwrap_or_default(); - let (cfg, block, at) = self.evm_env_at(block_id).await?; let state = self.state_at(at)?; let mut env = build_call_evm_env(cfg, block, request.clone())?; diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index f5d3375f6108..3d0dff5f8749 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -310,9 +310,10 @@ where return Ok(pending.origin.into_actual_pending()) } + let mut lock = self.inner.pending_block.lock().await; + // no pending block from the CL yet, so we need to build it ourselves via txpool - self.on_blocking_task(|this| async move { - let mut lock = this.inner.pending_block.lock().await; + self.on_blocking_task(move |this| { let now = Instant::now(); // check if the block is still good @@ -416,15 +417,21 @@ where } } -impl CallBlocking - for EthApi -{ - fn spawn_blocking(&self, f: Pin>) - where - F: Future + Send + 'static, - { - _ = self.inner.task_spawner().spawn_blocking(f); - } +impl CallBlocking for EthApi { + fn spawn_blocking(&self, f: F) -> impl Future> + Send + where + Self: Sized, + F: FnOnce(Self) -> EthResult + Send + 'static, + T: Send + 'static, + { + let this = self.clone(); + let fut = self.inner + .blocking_task_pool() + .spawn(move || f(this)); + async move { + fut.await.map_err(|_| EthApiError::InternalBlockingTaskError) + } + } } /// The default gas limit for eth_call and adjacent calls. @@ -507,4 +514,10 @@ impl EthApiInner &dyn TaskSpawner { &*self.task_spawner } + + /// Returns a handle to the blocking thread pool. + #[inline] + pub const fn blocking_task_pool(&self) -> &BlockingTaskPool { + &self.blocking_task_pool + } } diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 15a602e6c487..5cc724036ae3 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -33,7 +33,7 @@ use super::{BuildReceipt, EthApiSpec}; #[async_trait::async_trait] impl EthApiServer for EthApi where - Self: EthApiSpec + EthTransactions + BuildReceipt, + Self: EthApiSpec + EthTransactions + BuildReceipt + CallBlocking, Pool: TransactionPool + 'static, Provider: BlockReaderIdExt + ChainSpecProvider @@ -214,7 +214,7 @@ where /// Handler for: `eth_getBalance` async fn balance(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(self.on_blocking_task(|this| async move { this.balance(address, block_number) }).await?) + Ok(CallBlocking::spawn_blocking(self, move |this| this.balance(address, block_number)).await?) } /// Handler for: `eth_getStorageAt` @@ -225,9 +225,9 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - Ok(self - .on_blocking_task(|this| async move { this.storage_at(address, index, block_number) }) - .await?) + let res: B256 = CallBlocking::spawn_blocking(self, move |this| this.storage_at(address, index, block_number) ) + .await?; + Ok(res) } /// Handler for: `eth_getTransactionCount` @@ -237,18 +237,14 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(self - .on_blocking_task( - |this| async move { this.get_transaction_count(address, block_number) }, - ) + Ok(CallBlocking::spawn_blocking(self, move |this| this.get_transaction_count(address, block_number)) .await?) } /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(self - .on_blocking_task(|this| async move { this.get_code(address, block_number) }) + Ok(CallBlocking::spawn_blocking(self, move |this| this.get_code(address, block_number)) .await?) } diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 461d5bbda811..d02034388c26 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -3,37 +3,17 @@ use std::pin::Pin; use futures::Future; +use reth_primitives::Block; use tokio::sync::oneshot; use crate::eth::error::{EthApiError, EthResult}; /// Calls a blocking task on a new blocking thread. pub trait CallBlocking { - /// Spawns a blocking task. - fn spawn_blocking(&self, f: Pin>) - where - F: Future + Send + 'static; - /// Executes the future on a new blocking task. - /// - /// This accepts a closure that creates a new future using a clone of this type and spawns the - /// future onto a new task that is allowed to block. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations. - fn on_blocking_task(&self, c: C) -> impl Future> - where - Self: Clone + Send + 'static, - C: FnOnce(Self) -> F, - F: Future> + Send + 'static, - R: Send + 'static, - { - let (tx, rx) = oneshot::channel(); - let this = self.clone(); - let f = c(this); - self.spawn_blocking(Box::pin(async move { - let res = f.await; - let _ = tx.send(res); - })); - - async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } - } + /// Queues the closure for execution on the blocking thread pool. + fn spawn_blocking(&self, f: F) -> impl Future> + Send + where + Self: Sized, + F: FnOnce(Self) -> EthResult + Send + 'static, + T: Send + 'static; } diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index d12bd094ae0f..9176812e6b4b 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -125,24 +125,6 @@ pub trait EthTransactions: Send + Sync { /// Returns default gas limit to use for `eth_call` and tracing RPC methods. fn call_gas_limit(&self) -> u64; - /// Executes the future on a new blocking task. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing - /// or CPU bound operations in general use [Self::spawn_blocking]. - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static; - - /// Executes a blocking on the tracing pol. - /// - /// Note: This is expected for futures that are predominantly CPU bound, for blocking IO futures - /// use [Self::spawn_blocking_future]. - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static; - /// Returns the state at the given [BlockId] fn state_at(&self, at: BlockId) -> EthResult; diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index a561f4f510dc..1b8c713e48eb 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -152,22 +152,6 @@ where self.inner.gas_cap } - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static, - { - self.on_blocking_task(|_| c).await - } - - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static, - { - self.spawn_tracing_task_with(move |_| c()).await - } - fn state_at(&self, at: BlockId) -> EthResult { self.state_at_block_id(at) } @@ -185,7 +169,7 @@ where F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, T: Send + 'static, { - self.spawn_tracing_task_with(move |this| { + self.spawn_blocking(move |this| { let state = this.state_at(at)?; f(state) }) @@ -256,7 +240,7 @@ where return Ok(Some(tx)) } - self.on_blocking_task(|this| async move { + self.on_blocking_task(move |this| { Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) }) .await @@ -265,7 +249,7 @@ where async fn transaction_by_hash(&self, hash: B256) -> EthResult> { // Try to find the transaction on disk let mut resp = self - .on_blocking_task(|this| async move { + .on_blocking_task(move |this| { match this.provider().transaction_by_hash_with_meta(hash)? { None => Ok(None), Some((tx, meta)) => { @@ -809,7 +793,7 @@ where } // replay all transactions of the block - self.spawn_tracing_task_with(move |this| { + self.spawn_blocking(move |this| { // we need to get the state of the parent block because we're replaying this block on // top of its parent block's state let state_at = block.parent_hash; @@ -887,20 +871,6 @@ where Network: NetworkInfo + 'static, EvmConfig: ConfigureEvm, { - /// Spawns the given closure on a new blocking tracing task - async fn spawn_tracing_task_with(&self, f: F) -> EthResult - where - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static, - { - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || f(this)) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } - /// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy /// transactions. pub(crate) async fn legacy_gas_price(&self, gas_price: Option) -> EthResult { diff --git a/crates/rpc/rpc/src/reth.rs b/crates/rpc/rpc/src/reth.rs index 87865ef31fd4..f25a626f3ae6 100644 --- a/crates/rpc/rpc/src/reth.rs +++ b/crates/rpc/rpc/src/reth.rs @@ -57,7 +57,7 @@ where &self, block_id: BlockId, ) -> EthResult> { - self.on_blocking_task(|this| async move { this.try_balance_changes_in_block(block_id) }) + self.spawn_blocking(|this| async move { this.try_balance_changes_in_block(block_id) }) .await } From c35b40eac3e7b4b9073b193b82f12e28aca46b63 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 15:23:19 +0200 Subject: [PATCH 03/33] Update docs and symbol name --- crates/rpc/rpc/src/eth/api/call.rs | 15 +-- crates/rpc/rpc/src/eth/api/mod.rs | 106 +++++++++--------- crates/rpc/rpc/src/eth/api/server.rs | 19 ++-- .../rpc/src/eth/api/traits/blocking_task.rs | 20 ++-- crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 +- .../rpc/rpc/src/eth/api/traits/transaction.rs | 10 +- crates/rpc/rpc/src/eth/api/transactions.rs | 9 +- crates/rpc/rpc/src/reth.rs | 2 +- 8 files changed, 90 insertions(+), 93 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 05af642841de..168a7642fa8e 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -2,7 +2,7 @@ use crate::{ eth::{ - api::{CallBlocking, EthTransactions}, + api::{EthTransactions, SpawnBlocking}, error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError}, revm_utils::{ apply_state_overrides, build_call_evm_env, caller_gas_allowance, @@ -58,11 +58,11 @@ where ) -> EthResult { let (cfg, block_env, at) = self.evm_env_at(at).await?; - self.on_blocking_task(|this| Box::pin(async move { + self.spawn_blocking(move |this| { let state = this.state_at(at)?; this.estimate_gas_with(cfg, block_env, request, state, state_override) - })) - .await? + }) + .await } /// Executes the call request (`eth_call`) and returns the output @@ -376,13 +376,10 @@ where let block_id = block_number.unwrap_or_default(); let (cfg, block, at) = self.evm_env_at(block_id).await?; - self.on_blocking_task(|this| async move { - this.create_access_list_with(cfg, block, at, request).await - }) - .await? + self.spawn_blocking(move |this| this.create_access_list_with(cfg, block, at, request)).await } - async fn create_access_list_with( + fn create_access_list_with( &self, cfg: CfgEnvWithHandlerCfg, block: BlockEnv, diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 3d0dff5f8749..61207b8e65e1 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -1,8 +1,6 @@ //! The entire implementation of the namespace is quite large, hence it is divided across several //! files. -use std::pin::Pin; - use async_trait::async_trait; use reth_errors::{RethError, RethResult}; use reth_evm::ConfigureEvm; @@ -26,7 +24,7 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::Mutex; -use traits::CallBlocking; +use traits::SpawnBlocking; use crate::eth::{ api::{ @@ -311,40 +309,42 @@ where } let mut lock = self.inner.pending_block.lock().await; - + + let now = Instant::now(); + + // check if the block is still good + if let Some(pending_block) = lock.as_ref() { + // this is guaranteed to be the `latest` header + if pending.block_env.number.to::() == pending_block.block.number && + pending.origin.header().hash() == pending_block.block.parent_hash && + now <= pending_block.expires_at + { + return Ok(Some(pending_block.block.clone())) + } + } + // no pending block from the CL yet, so we need to build it ourselves via txpool - self.on_blocking_task(move |this| { - let now = Instant::now(); - - // check if the block is still good - if let Some(pending_block) = lock.as_ref() { - // this is guaranteed to be the `latest` header - if pending.block_env.number.to::() == pending_block.block.number && - pending.origin.header().hash() == pending_block.block.parent_hash && - now <= pending_block.expires_at - { - return Ok(Some(pending_block.block.clone())) - } + let pending_block = match self + .spawn_blocking(move |this| { + // we rebuild the block + pending.build_block(this.provider(), this.pool()) + }) + .await + { + Ok(block) => block, + Err(err) => { + tracing::debug!(target: "rpc", "Failed to build pending block: {:?}", err); + return Ok(None) } + }; + + let now = Instant::now(); + *lock = Some(PendingBlock { + block: pending_block.clone(), + expires_at: now + Duration::from_secs(1), + }); - // we rebuild the block - let pending_block = match pending.build_block(this.provider(), this.pool()) { - Ok(block) => block, - Err(err) => { - tracing::debug!(target: "rpc", "Failed to build pending block: {:?}", err); - return Ok(None) - } - }; - - let now = Instant::now(); - *lock = Some(PendingBlock { - block: pending_block.clone(), - expires_at: now + Duration::from_secs(1), - }); - - Ok(Some(pending_block)) - }) - .await + Ok(Some(pending_block)) } } @@ -417,21 +417,21 @@ where } } -impl CallBlocking for EthApi { - fn spawn_blocking(&self, f: F) -> impl Future> + Send - where +impl SpawnBlocking + for EthApi +where + Self: Send + Sync + 'static, +{ + fn spawn_blocking(&self, f: F) -> impl Future> + Send + where Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static, - { - let this = self.clone(); - let fut = self.inner - .blocking_task_pool() - .spawn(move || f(this)); - async move { - fut.await.map_err(|_| EthApiError::InternalBlockingTaskError) - } - } + F: FnOnce(Self) -> EthResult + Send + 'static, + T: Send + 'static, + { + let this = self.clone(); + let fut = self.inner.blocking_task_pool().spawn(move || f(this)); + async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? } + } } /// The default gas limit for eth_call and adjacent calls. @@ -515,9 +515,9 @@ impl EthApiInner &BlockingTaskPool { - &self.blocking_task_pool - } + /// Returns a handle to the blocking thread pool. + #[inline] + pub const fn blocking_task_pool(&self) -> &BlockingTaskPool { + &self.blocking_task_pool + } } diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 5cc724036ae3..5bb1790c9e87 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -20,7 +20,7 @@ use tracing::trace; use crate::{ eth::{ - api::{CallBlocking, EthBlocks, EthTransactions}, + api::{EthBlocks, EthTransactions, SpawnBlocking}, error::EthApiError, revm_utils::EvmOverrides, EthApi, @@ -33,7 +33,7 @@ use super::{BuildReceipt, EthApiSpec}; #[async_trait::async_trait] impl EthApiServer for EthApi where - Self: EthApiSpec + EthTransactions + BuildReceipt + CallBlocking, + Self: EthApiSpec + EthTransactions + BuildReceipt + SpawnBlocking, Pool: TransactionPool + 'static, Provider: BlockReaderIdExt + ChainSpecProvider @@ -214,7 +214,8 @@ where /// Handler for: `eth_getBalance` async fn balance(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(CallBlocking::spawn_blocking(self, move |this| this.balance(address, block_number)).await?) + Ok(SpawnBlocking::spawn_blocking(self, move |this| this.balance(address, block_number)) + .await?) } /// Handler for: `eth_getStorageAt` @@ -225,7 +226,9 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - let res: B256 = CallBlocking::spawn_blocking(self, move |this| this.storage_at(address, index, block_number) ) + let res: B256 = SpawnBlocking::spawn_blocking(self, move |this| { + this.storage_at(address, index, block_number) + }) .await?; Ok(res) } @@ -237,14 +240,16 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(CallBlocking::spawn_blocking(self, move |this| this.get_transaction_count(address, block_number)) - .await?) + Ok(SpawnBlocking::spawn_blocking(self, move |this| { + this.get_transaction_count(address, block_number) + }) + .await?) } /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(CallBlocking::spawn_blocking(self, move |this| this.get_code(address, block_number)) + Ok(SpawnBlocking::spawn_blocking(self, move |this| this.get_code(address, block_number)) .await?) } diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index d02034388c26..f09748874af2 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -1,19 +1,15 @@ //! Spawns a blocking task. Should be used for long-lived database reads. -use std::pin::Pin; - use futures::Future; -use reth_primitives::Block; -use tokio::sync::oneshot; -use crate::eth::error::{EthApiError, EthResult}; +use crate::eth::error::EthResult; -/// Calls a blocking task on a new blocking thread. -pub trait CallBlocking { - /// Queues the closure for execution on the blocking thread pool. - fn spawn_blocking(&self, f: F) -> impl Future> + Send - where +/// Executes code on a blocking thread. +pub trait SpawnBlocking { + /// Executes closure on a blocking thread. + fn spawn_blocking(&self, f: F) -> impl Future> + Send + where Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static; + F: FnOnce(Self) -> EthResult + Send + 'static, + T: Send + 'static; } diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index 9c4c97c94856..505f7c106648 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -6,6 +6,6 @@ pub mod receipt; pub mod transaction; pub use block::EthBlocks; -pub use blocking_task::CallBlocking; +pub use blocking_task::SpawnBlocking; pub use receipt::BuildReceipt; pub use transaction::{EthTransactions, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 9176812e6b4b..9addfb9ea52d 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -1,8 +1,6 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. -use std::future::Future; - use crate::eth::{ error::{EthApiError, EthResult}, revm_utils::EvmOverrides, @@ -28,6 +26,8 @@ use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use crate::eth::{api::BuildReceipt, revm_utils::FillableTransaction}; use revm_primitives::db::{Database, DatabaseRef}; +use super::SpawnBlocking; + /// Helper alias type for the state's [`CacheDB`] pub type StateCacheDB = CacheDB>; @@ -219,7 +219,7 @@ pub trait EthTransactions: Send + Sync { /// Note: The tx receipt is not available for pending transactions. async fn transaction_receipt(&self, hash: B256) -> EthResult> where - Self: BuildReceipt + Clone + 'static, + Self: BuildReceipt + SpawnBlocking + Clone + 'static, { let result = self.load_transaction_and_receipt(hash).await?; @@ -237,10 +237,10 @@ pub trait EthTransactions: Send + Sync { hash: TxHash, ) -> EthResult> where - Self: Clone + 'static, + Self: SpawnBlocking + Clone + 'static, { let this = self.clone(); - self.spawn_blocking_future(async move { + self.spawn_blocking(move |_| { let (tx, meta) = match this.provider().transaction_by_hash_with_meta(hash)? { Some((tx, meta)) => (tx, meta), None => return Ok(None), diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 1b8c713e48eb..4690bb189c2e 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -1,7 +1,7 @@ //! Contains RPC handler implementations specific to transactions use crate::{ eth::{ - api::{pending_block::PendingBlockEnv, CallBlocking}, + api::{pending_block::PendingBlockEnv, SpawnBlocking}, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, revm_utils::{prepare_call_env, EvmOverrides}, @@ -43,7 +43,6 @@ use revm::{ GetInspector, Inspector, }; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; -use std::future::Future; use crate::eth::{ api::{BuildReceipt, EthTransactions, StateCacheDB}, @@ -240,7 +239,7 @@ where return Ok(Some(tx)) } - self.on_blocking_task(move |this| { + self.spawn_blocking(move |this| { Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) }) .await @@ -249,7 +248,7 @@ where async fn transaction_by_hash(&self, hash: B256) -> EthResult> { // Try to find the transaction on disk let mut resp = self - .on_blocking_task(move |this| { + .spawn_blocking(move |this| { match this.provider().transaction_by_hash_with_meta(hash)? { None => Ok(None), Some((tx, meta)) => { @@ -329,7 +328,7 @@ where async fn transaction_receipt(&self, hash: B256) -> EthResult> where - Self: BuildReceipt + Clone + Send + 'static, + Self: BuildReceipt + SpawnBlocking + Clone + Send + 'static, { let result = self.load_transaction_and_receipt(hash).await?; diff --git a/crates/rpc/rpc/src/reth.rs b/crates/rpc/rpc/src/reth.rs index f25a626f3ae6..87865ef31fd4 100644 --- a/crates/rpc/rpc/src/reth.rs +++ b/crates/rpc/rpc/src/reth.rs @@ -57,7 +57,7 @@ where &self, block_id: BlockId, ) -> EthResult> { - self.spawn_blocking(|this| async move { this.try_balance_changes_in_block(block_id) }) + self.on_blocking_task(|this| async move { this.try_balance_changes_in_block(block_id) }) .await } From 8ccddd395edc0afebcb85f599ef5d3e255715aae Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 16:31:34 +0200 Subject: [PATCH 04/33] Add missing reth primitives to op feature --- crates/storage/db/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index 3a9ea5be50a7..7eb2b90be180 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -88,7 +88,7 @@ arbitrary = [ "dep:proptest", "dep:proptest-derive", ] -optimism = [] +optimism = ["reth-primitives/optimism"] [[bench]] name = "hash_keys" From 257dc5dd97903bb04df228159ecbcff6e6d19f7f Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 16:40:35 +0200 Subject: [PATCH 05/33] Remove feature gate to fix broken test --- crates/evm/execution-types/src/bundle.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/evm/execution-types/src/bundle.rs b/crates/evm/execution-types/src/bundle.rs index 9952d5de4d11..b8f5d1eb4119 100644 --- a/crates/evm/execution-types/src/bundle.rs +++ b/crates/evm/execution-types/src/bundle.rs @@ -174,11 +174,8 @@ impl BundleStateWithReceipts { /// Returns the receipt root for all recorded receipts. /// Note: this function calculated Bloom filters for every receipt and created merkle trees /// of receipt. This is a expensive operation. - pub fn receipts_root_slow(&self, _block_number: BlockNumber) -> Option { - #[cfg(feature = "optimism")] - panic!("This should not be called in optimism mode. Use `optimism_receipts_root_slow` instead."); - #[cfg(not(feature = "optimism"))] - self.receipts.root_slow(self.block_number_to_index(_block_number)?) + pub fn receipts_root_slow(&self, block_number: BlockNumber) -> Option { + self.receipts.root_slow(self.block_number_to_index(block_number)?) } /// Returns the receipt root for all recorded receipts. From 40194d6dfe237b7bb109cbc74f00354f337ccb5a Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 16:56:35 +0200 Subject: [PATCH 06/33] Fix flaky test --- .../storage/db/src/tables/codecs/compact.rs | 125 +++++++++--------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/crates/storage/db/src/tables/codecs/compact.rs b/crates/storage/db/src/tables/codecs/compact.rs index 907fb2146528..06372bd2e907 100644 --- a/crates/storage/db/src/tables/codecs/compact.rs +++ b/crates/storage/db/src/tables/codecs/compact.rs @@ -149,70 +149,69 @@ mod tests { // // this check is to ensure we do not inadvertently add too many fields to a struct which would // expand the flags field and break backwards compatibility + #[cfg(not(feature = "optimism"))] #[test] fn test_ensure_backwards_compatibility() { - #[cfg(not(feature = "optimism"))] - { - assert_eq!(Account::bitflag_encoded_bytes(), 2); - assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); - assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); - assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); - assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); - assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(Header::bitflag_encoded_bytes(), 4); - assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); - assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); - assert_eq!(Receipt::bitflag_encoded_bytes(), 1); - assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); - assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); - assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); - assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); - assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); - assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); - assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); - assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); - assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); - } - - #[cfg(feature = "optimism")] - { - assert_eq!(Account::bitflag_encoded_bytes(), 2); - assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); - assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); - assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); - assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); - assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(Header::bitflag_encoded_bytes(), 4); - assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); - assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); - assert_eq!(Receipt::bitflag_encoded_bytes(), 2); - assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); - assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); - assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); - assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); - assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); - assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); - assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); - assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); - assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); - } + assert_eq!(Account::bitflag_encoded_bytes(), 2); + assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); + assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); + assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); + assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); + assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(Header::bitflag_encoded_bytes(), 4); + assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); + assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); + assert_eq!(Receipt::bitflag_encoded_bytes(), 1); + assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); + assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); + assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); + assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); + assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); + assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); + assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); + assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); + assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_ensure_backwards_compatibility() { + assert_eq!(Account::bitflag_encoded_bytes(), 2); + assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); + assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); + assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); + assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); + assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(Header::bitflag_encoded_bytes(), 4); + assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); + assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); + assert_eq!(Receipt::bitflag_encoded_bytes(), 1); + assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); + assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); + assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); + assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); + assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); + assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); + assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); + assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); + assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); } } From 68e64b4e65e6f60df192dcff8ab66d5433be4e16 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 16:58:29 +0200 Subject: [PATCH 07/33] fixup! Fix flaky test --- crates/storage/db/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index 7eb2b90be180..6b579dbdbf0e 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -88,7 +88,7 @@ arbitrary = [ "dep:proptest", "dep:proptest-derive", ] -optimism = ["reth-primitives/optimism"] +optimism = ["reth-primitives/optimism", "reth-codecs/optimism"] [[bench]] name = "hash_keys" From 30b63cc49fc0ac3689e95590a285782694aa1720 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 17:27:56 +0200 Subject: [PATCH 08/33] fixup! Fix flaky test --- crates/storage/db/src/tables/codecs/compact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/db/src/tables/codecs/compact.rs b/crates/storage/db/src/tables/codecs/compact.rs index 06372bd2e907..bd927f96e674 100644 --- a/crates/storage/db/src/tables/codecs/compact.rs +++ b/crates/storage/db/src/tables/codecs/compact.rs @@ -199,7 +199,7 @@ mod tests { assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); - assert_eq!(Receipt::bitflag_encoded_bytes(), 1); + assert_eq!(Receipt::bitflag_encoded_bytes(), 2); assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); From fcc64ea1da8b04cb8b568274061644dbb67c5a73 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 1 Jun 2024 17:29:06 +0200 Subject: [PATCH 09/33] Update lock file --- Cargo.lock | 184 ++++++++++++++--------------------- crates/storage/db/Cargo.toml | 5 +- 2 files changed, 79 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ebd458eb375..b984c5c9b961 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "alloy-consensus" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#dd7a999d9efe259c47a34dde046952de795a8f6a" +source = "git+https://github.com/alloy-rs/alloy#4ecb7d86882ece8a9a7a5a892b71a3c198030731" dependencies = [ "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", "alloy-primitives", @@ -165,7 +165,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.6.8", + "winnow 0.6.9", ] [[package]] @@ -189,7 +189,7 @@ dependencies = [ [[package]] name = "alloy-eips" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#dd7a999d9efe259c47a34dde046952de795a8f6a" +source = "git+https://github.com/alloy-rs/alloy#4ecb7d86882ece8a9a7a5a892b71a3c198030731" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "alloy-genesis" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#dd7a999d9efe259c47a34dde046952de795a8f6a" +source = "git+https://github.com/alloy-rs/alloy#4ecb7d86882ece8a9a7a5a892b71a3c198030731" dependencies = [ "alloy-primitives", "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" +checksum = "8037e03c7f462a063f28daec9fda285a9a89da003c552f8637a80b9c8fd96241" dependencies = [ "proc-macro2", "quote", @@ -405,7 +405,7 @@ dependencies = [ [[package]] name = "alloy-rpc-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#dd7a999d9efe259c47a34dde046952de795a8f6a" +source = "git+https://github.com/alloy-rs/alloy#4ecb7d86882ece8a9a7a5a892b71a3c198030731" dependencies = [ "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy)", "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -486,7 +486,7 @@ dependencies = [ [[package]] name = "alloy-serde" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#dd7a999d9efe259c47a34dde046952de795a8f6a" +source = "git+https://github.com/alloy-rs/alloy#4ecb7d86882ece8a9a7a5a892b71a3c198030731" dependencies = [ "alloy-primitives", "serde", @@ -579,7 +579,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368cae4dc052cad1d8f72eb2ae0c38027116933eeb49213c200a9e9875f208d7" dependencies = [ - "winnow 0.6.8", + "winnow 0.6.9", ] [[package]] @@ -907,22 +907,21 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-compression" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" dependencies = [ "brotli", "flate2", @@ -934,17 +933,6 @@ dependencies = [ "zstd-safe", ] -[[package]] -name = "async-lock" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" -dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", - "pin-project-lite", -] - [[package]] name = "async-sse" version = "5.1.0" @@ -1045,9 +1033,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -1259,12 +1247,11 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "async-channel 2.3.0", - "async-lock", + "async-channel 2.3.1", "async-task", "futures-io", "futures-lite 2.3.0", @@ -1273,9 +1260,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" dependencies = [ "cc", "glob", @@ -1429,9 +1416,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1496,9 +1483,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "369cfaf2a5bed5d8f8202073b2e093c9f508251de1551a0deb4253e4c7d80909" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", @@ -1676,9 +1663,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -1852,9 +1839,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.11.4" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if", "cpufeatures", @@ -2764,9 +2751,9 @@ dependencies = [ [[package]] name = "ethereum_ssz" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e61ffea29f26e8249d35128a82ec8d3bd4fbc80179ea5f5e5e3daafef6a80fcb" +checksum = "7d3627f83d8b87b432a5fad9934b4565260722a141a2c40f371f8080adec9425" dependencies = [ "ethereum-types", "itertools 0.10.5", @@ -2781,43 +2768,22 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -3224,9 +3190,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glob" @@ -3663,9 +3629,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -3786,9 +3752,9 @@ checksum = "545c6c3e8bf9580e2dafee8de6f9ec14826aaf359787789c7724f1f85f47d3dc" [[package]] name = "icu_normalizer" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183072b0ba2f336279c830a3d594a04168494a726c3c94b50c53d788178cf2c2" +checksum = "accb85c5b2e76f8dade22978b3795ae1e550198c6cfc7e915144e17cd6e2ab56" dependencies = [ "displaydoc", "icu_collections", @@ -3810,9 +3776,9 @@ checksum = "e3744fecc0df9ce19999cdaf1f9f3a48c253431ce1d67ef499128fe9d0b607ab" [[package]] name = "icu_properties" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a89401989d8fdf571b829ce1022801367ec89affc7b1e162b79eff4ae029e69" +checksum = "d8173ba888885d250016e957b8ebfd5a65cdb690123d8833a19f6833f9c2b579" dependencies = [ "displaydoc", "icu_collections", @@ -4634,9 +4600,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" @@ -5210,9 +5176,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -5506,9 +5472,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand 2.1.0", @@ -9391,9 +9357,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", @@ -9432,9 +9398,9 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -9451,9 +9417,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -9550,7 +9516,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.9", ] [[package]] @@ -10421,9 +10387,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] @@ -10456,9 +10422,9 @@ checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad7bb64b8ef9c0aa27b6da38b452b0ee9fd82beaf276a87dd796fb55cbae14e" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wyhash" @@ -10480,9 +10446,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", @@ -10492,9 +10458,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", @@ -10524,18 +10490,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", @@ -10565,9 +10531,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff4439ae91fb5c72b8abc12f3f2dbf51bd27e6eadb9f8a5bc8898dddb0e27ea" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" dependencies = [ "yoke", "zerofrom", @@ -10576,9 +10542,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index 6b579dbdbf0e..4acfa8050292 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -88,7 +88,10 @@ arbitrary = [ "dep:proptest", "dep:proptest-derive", ] -optimism = ["reth-primitives/optimism", "reth-codecs/optimism"] +optimism = [ + "reth-primitives/optimism", + "reth-codecs/optimism" +] [[bench]] name = "hash_keys" From 734ac99e1c1db4bd117f027af7debab1e88547fe Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 4 Jun 2024 23:23:48 +0200 Subject: [PATCH 10/33] Reinsert functions for spawning blocking threads into EthTransactions --- .../rpc/rpc/src/eth/api/traits/transaction.rs | 18 ++++++++++++++++++ crates/rpc/rpc/src/eth/api/transactions.rs | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 9addfb9ea52d..242b16928d47 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -125,6 +125,24 @@ pub trait EthTransactions: Send + Sync { /// Returns default gas limit to use for `eth_call` and tracing RPC methods. fn call_gas_limit(&self) -> u64; + /// Executes the future on a new blocking task. + /// + /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing + /// or CPU bound operations in general use [Self::spawn_blocking]. + async fn spawn_blocking_future(&self, c: F) -> EthResult + where + F: Future> + Send + 'static, + R: Send + 'static; + + /// Executes a blocking on the tracing pol. + /// + /// Note: This is expected for futures that are predominantly CPU bound, for blocking IO futures + /// use [Self::spawn_blocking_future]. + async fn spawn_blocking(&self, c: F) -> EthResult + where + F: FnOnce() -> EthResult + Send + 'static, + R: Send + 'static; + /// Returns the state at the given [BlockId] fn state_at(&self, at: BlockId) -> EthResult; diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 4690bb189c2e..58251561a6d9 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -151,6 +151,22 @@ where self.inner.gas_cap } + async fn spawn_blocking_future(&self, c: F) -> EthResult + where + F: Future> + Send + 'static, + R: Send + 'static, + { + self.on_blocking_task(|_| c).await + } + + async fn spawn_blocking(&self, c: F) -> EthResult + where + F: FnOnce() -> EthResult + Send + 'static, + R: Send + 'static, + { + self.spawn_tracing_task_with(move |_| c()).await + } + fn state_at(&self, at: BlockId) -> EthResult { self.state_at_block_id(at) } From c000f4364bbdf0009fcc15b3503bc76503b2227f Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 4 Jun 2024 22:27:30 +0200 Subject: [PATCH 11/33] Drive-by, update docs --- crates/rpc/rpc/src/eth/api/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 7 ++++--- crates/tasks/src/pool.rs | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 61207b8e65e1..c21bd20a06fc 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -486,7 +486,7 @@ pub struct EthApiInner { task_spawner: Box, /// Cached pending block if any pending_block: Mutex>, - /// A pool dedicated to blocking tasks. + /// A pool dedicated to CPU heavy blocking tasks. blocking_task_pool: BlockingTaskPool, /// Cache for block fees history fee_history_cache: FeeHistoryCache, diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 242b16928d47..7a92be57749c 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -134,10 +134,11 @@ pub trait EthTransactions: Send + Sync { F: Future> + Send + 'static, R: Send + 'static; - /// Executes a blocking on the tracing pol. + /// Executes a blocking task on the tracing pool. /// - /// Note: This is expected for futures that are predominantly CPU bound, for blocking IO futures - /// use [Self::spawn_blocking_future]. + /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` + /// under the hood, for blocking IO futures use [Self::spawn_blocking_future]. See + /// . async fn spawn_blocking(&self, c: F) -> EthResult where F: FnOnce() -> EthResult + Send + 'static, diff --git a/crates/tasks/src/pool.rs b/crates/tasks/src/pool.rs index a96b53b824a0..4213451fd506 100644 --- a/crates/tasks/src/pool.rs +++ b/crates/tasks/src/pool.rs @@ -43,7 +43,8 @@ impl BlockingTaskGuard { /// /// This is a dedicated threadpool for blocking tasks which are CPU bound. /// RPC calls that perform blocking IO (disk lookups) are not executed on this pool but on the tokio -/// runtime's blocking pool, which performs poorly with CPU bound tasks. Once the tokio blocking +/// runtime's blocking pool, which performs poorly with CPU bound tasks (see +/// ). Once the tokio blocking /// pool is saturated it is converted into a queue, blocking tasks could then interfere with the /// queue and block other RPC calls. /// From d1b91ade2ac137b6d48bb9ad14c7ba13e61a4a81 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 4 Jun 2024 23:34:19 +0200 Subject: [PATCH 12/33] Move spawn cpu heavy to trait --- crates/rpc/rpc/src/debug.rs | 4 +-- crates/rpc/rpc/src/eth/api/call.rs | 5 +-- crates/rpc/rpc/src/eth/api/mod.rs | 20 +++++++++-- crates/rpc/rpc/src/eth/api/server.rs | 8 ++--- .../rpc/src/eth/api/traits/blocking_task.rs | 18 ++++++++-- .../rpc/rpc/src/eth/api/traits/transaction.rs | 29 ++++------------ crates/rpc/rpc/src/eth/api/transactions.rs | 34 +++++++------------ 7 files changed, 62 insertions(+), 56 deletions(-) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 5d37fc5a222b..fe46e84b73df 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,6 +1,6 @@ use crate::{ eth::{ - api::EthTransactions, + api::{traits::SpawnBlocking, EthTransactions}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, }, @@ -614,7 +614,7 @@ where impl DebugApiServer for DebugApi where Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthApiSpec + 'static, + Eth: EthApiSpec + SpawnBlocking + 'static, { /// Handler for `debug_getRawHeader` async fn raw_header(&self, block_id: BlockId) -> RpcResult { diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 168a7642fa8e..d90c2e3cdfa0 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -58,7 +58,7 @@ where ) -> EthResult { let (cfg, block_env, at) = self.evm_env_at(at).await?; - self.spawn_blocking(move |this| { + self.spawn_blocking_io(move |this| { let state = this.state_at(at)?; this.estimate_gas_with(cfg, block_env, request, state, state_override) }) @@ -376,7 +376,8 @@ where let block_id = block_number.unwrap_or_default(); let (cfg, block, at) = self.evm_env_at(block_id).await?; - self.spawn_blocking(move |this| this.create_access_list_with(cfg, block, at, request)).await + self.spawn_blocking_io(move |this| this.create_access_list_with(cfg, block, at, request)) + .await } fn create_access_list_with( diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index c21bd20a06fc..59888392c785 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -325,7 +325,7 @@ where // no pending block from the CL yet, so we need to build it ourselves via txpool let pending_block = match self - .spawn_blocking(move |this| { + .spawn_blocking_io(move |this| { // we rebuild the block pending.build_block(this.provider(), this.pool()) }) @@ -422,7 +422,7 @@ impl SpawnBlocking where Self: Send + Sync + 'static, { - fn spawn_blocking(&self, f: F) -> impl Future> + Send + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where Self: Sized, F: FnOnce(Self) -> EthResult + Send + 'static, @@ -432,6 +432,22 @@ where let fut = self.inner.blocking_task_pool().spawn(move || f(this)); async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? } } + + fn spawn_tracing(&self, f: F) -> impl Future> + where + Self: Sized, + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static, + { + let this = self.clone(); + async move { + self.inner + .blocking_task_pool + .spawn(move || f(this)) + .await + .map_err(|_| EthApiError::InternalBlockingTaskError)? + } + } } /// The default gas limit for eth_call and adjacent calls. diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 5bb1790c9e87..322ee7f0da0e 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -214,7 +214,7 @@ where /// Handler for: `eth_getBalance` async fn balance(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(SpawnBlocking::spawn_blocking(self, move |this| this.balance(address, block_number)) + Ok(SpawnBlocking::spawn_blocking_io(self, move |this| this.balance(address, block_number)) .await?) } @@ -226,7 +226,7 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - let res: B256 = SpawnBlocking::spawn_blocking(self, move |this| { + let res: B256 = SpawnBlocking::spawn_blocking_io(self, move |this| { this.storage_at(address, index, block_number) }) .await?; @@ -240,7 +240,7 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(SpawnBlocking::spawn_blocking(self, move |this| { + Ok(SpawnBlocking::spawn_blocking_io(self, move |this| { this.get_transaction_count(address, block_number) }) .await?) @@ -249,7 +249,7 @@ where /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(SpawnBlocking::spawn_blocking(self, move |this| this.get_code(address, block_number)) + Ok(SpawnBlocking::spawn_blocking_io(self, move |this| this.get_code(address, block_number)) .await?) } diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index f09748874af2..033a95a80e09 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -6,10 +6,24 @@ use crate::eth::error::EthResult; /// Executes code on a blocking thread. pub trait SpawnBlocking { - /// Executes closure on a blocking thread. - fn spawn_blocking(&self, f: F) -> impl Future> + Send + /// Executes the future on a new blocking task. + /// + /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing + /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where Self: Sized, F: FnOnce(Self) -> EthResult + Send + 'static, T: Send + 'static; + + /// Executes a blocking task on the tracing pool. + /// + /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` + /// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See + /// . + fn spawn_tracing(&self, f: F) -> impl Future> + where + Self: Sized, + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static; } diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 7a92be57749c..399bb6b46429 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -125,25 +125,6 @@ pub trait EthTransactions: Send + Sync { /// Returns default gas limit to use for `eth_call` and tracing RPC methods. fn call_gas_limit(&self) -> u64; - /// Executes the future on a new blocking task. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing - /// or CPU bound operations in general use [Self::spawn_blocking]. - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static; - - /// Executes a blocking task on the tracing pool. - /// - /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` - /// under the hood, for blocking IO futures use [Self::spawn_blocking_future]. See - /// . - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static; - /// Returns the state at the given [BlockId] fn state_at(&self, at: BlockId) -> EthResult; @@ -209,14 +190,18 @@ pub trait EthTransactions: Send + Sync { /// Checks the pool and state. /// /// Returns `Ok(None)` if no matching transaction was found. - async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult>; + async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> + where + Self: SpawnBlocking; /// Returns the transaction by hash. /// /// Checks the pool and state. /// /// Returns `Ok(None)` if no matching transaction was found. - async fn transaction_by_hash(&self, hash: B256) -> EthResult>; + async fn transaction_by_hash(&self, hash: B256) -> EthResult> + where + Self: SpawnBlocking; /// Returns the transaction by including its corresponding [BlockId] /// @@ -259,7 +244,7 @@ pub trait EthTransactions: Send + Sync { Self: SpawnBlocking + Clone + 'static, { let this = self.clone(); - self.spawn_blocking(move |_| { + self.spawn_blocking_io(move |_| { let (tx, meta) = match this.provider().transaction_by_hash_with_meta(hash)? { Some((tx, meta)) => (tx, meta), None => return Ok(None), diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 58251561a6d9..e09c78de5e47 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -151,22 +151,6 @@ where self.inner.gas_cap } - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static, - { - self.on_blocking_task(|_| c).await - } - - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static, - { - self.spawn_tracing_task_with(move |_| c()).await - } - fn state_at(&self, at: BlockId) -> EthResult { self.state_at_block_id(at) } @@ -184,7 +168,7 @@ where F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, T: Send + 'static, { - self.spawn_blocking(move |this| { + self.spawn_tracing(move |this| { let state = this.state_at(at)?; f(state) }) @@ -247,7 +231,10 @@ where self.block_by_id(block).await.map(|block| block.map(|block| block.body)) } - async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> { + async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> + where + Self: SpawnBlocking, + { // Note: this is mostly used to fetch pooled transactions so we check the pool first if let Some(tx) = self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded()) @@ -255,16 +242,19 @@ where return Ok(Some(tx)) } - self.spawn_blocking(move |this| { + self.spawn_blocking_io(move |this| { Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) }) .await } - async fn transaction_by_hash(&self, hash: B256) -> EthResult> { + async fn transaction_by_hash(&self, hash: B256) -> EthResult> + where + Self: SpawnBlocking, + { // Try to find the transaction on disk let mut resp = self - .spawn_blocking(move |this| { + .spawn_blocking_io(move |this| { match this.provider().transaction_by_hash_with_meta(hash)? { None => Ok(None), Some((tx, meta)) => { @@ -808,7 +798,7 @@ where } // replay all transactions of the block - self.spawn_blocking(move |this| { + self.spawn_tracing(move |this| { // we need to get the state of the parent block because we're replaying this block on // top of its parent block's state let state_at = block.parent_hash; From eec99b82b16af90878aa572269388afd28450b56 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 00:13:31 +0200 Subject: [PATCH 13/33] Fix lint --- crates/rpc/rpc/src/eth/api/mod.rs | 6 +++--- crates/rpc/rpc/src/eth/api/traits/blocking_task.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 59888392c785..c609f2219781 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -422,11 +422,11 @@ impl SpawnBlocking where Self: Send + Sync + 'static, { - fn spawn_blocking_io(&self, f: F) -> impl Future> + Send + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static, + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static, { let this = self.clone(); let fut = self.inner.blocking_task_pool().spawn(move || f(this)); diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 033a95a80e09..775dad9f4f0f 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -10,11 +10,11 @@ pub trait SpawnBlocking { /// /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). - fn spawn_blocking_io(&self, f: F) -> impl Future> + Send + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static; + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static; /// Executes a blocking task on the tracing pool. /// From 924024fd62c15f3b34b53bf981f17fa161882c1c Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 00:17:10 +0200 Subject: [PATCH 14/33] Revert impl for spawning blocking io --- crates/rpc/rpc/src/eth/api/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index c609f2219781..c799d538f7a6 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -23,7 +23,7 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use tokio::sync::Mutex; +use tokio::sync::{oneshot, Mutex}; use traits::SpawnBlocking; use crate::eth::{ @@ -428,9 +428,14 @@ where F: FnOnce(Self) -> EthResult + Send + 'static, R: Send + 'static, { + let (tx, rx) = oneshot::channel(); let this = self.clone(); - let fut = self.inner.blocking_task_pool().spawn(move || f(this)); - async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? } + self.inner.task_spawner.spawn_blocking(Box::pin(async move { + let res = async move { f(this) }.await; + let _ = tx.send(res); + })); + + async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } } fn spawn_tracing(&self, f: F) -> impl Future> From ea6cbd3c464a440fdaea2478a5c8bee199da40c1 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 00:35:06 +0200 Subject: [PATCH 15/33] Make impl of spawn blocking default trait methods --- crates/rpc/rpc/src/eth/api/mod.rs | 39 ++++-------------- .../rpc/src/eth/api/traits/blocking_task.rs | 41 ++++++++++++++++--- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index c799d538f7a6..e993c6d65ff2 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -19,11 +19,10 @@ use reth_transaction_pool::TransactionPool; use revm_primitives::{CfgEnv, SpecId}; use std::{ fmt::Debug, - future::Future, sync::Arc, time::{Duration, Instant}, }; -use tokio::sync::{oneshot, Mutex}; +use tokio::sync::Mutex; use traits::SpawnBlocking; use crate::eth::{ @@ -422,36 +421,12 @@ impl SpawnBlocking where Self: Send + Sync + 'static, { - fn spawn_blocking_io(&self, f: F) -> impl Future> + Send - where - Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - R: Send + 'static, - { - let (tx, rx) = oneshot::channel(); - let this = self.clone(); - self.inner.task_spawner.spawn_blocking(Box::pin(async move { - let res = async move { f(this) }.await; - let _ = tx.send(res); - })); - - async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } - } - - fn spawn_tracing(&self, f: F) -> impl Future> - where - Self: Sized, - F: FnOnce(Self) -> EthResult + Send + 'static, - R: Send + 'static, - { - let this = self.clone(); - async move { - self.inner - .blocking_task_pool - .spawn(move || f(this)) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } + fn io_task_spawner(&self) -> &dyn TaskSpawner { + self.inner.task_spawner() + } + + fn tracing_task_pool(&self) -> &BlockingTaskPool { + self.inner.blocking_task_pool() } } diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 775dad9f4f0f..31779d4c5660 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -1,20 +1,42 @@ //! Spawns a blocking task. Should be used for long-lived database reads. use futures::Future; +use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; +use tokio::sync::oneshot; -use crate::eth::error::EthResult; +use crate::eth::error::{EthApiError, EthResult}; /// Executes code on a blocking thread. pub trait SpawnBlocking { + /// Returns a handle for spawning IO heavy blocking tasks. + /// + /// Runtime access in default trait method implementations. + fn io_task_spawner(&self) -> &dyn TaskSpawner; + + /// Returns a handle for spawning CPU heavy blocking tasks. + /// + /// Runtime access in default trait method implementations. + fn tracing_task_pool(&self) -> &BlockingTaskPool; + /// Executes the future on a new blocking task. /// /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where - Self: Sized, + Self: Sized + Clone + Send + Sync + 'static, F: FnOnce(Self) -> EthResult + Send + 'static, - R: Send + 'static; + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + let this = self.clone(); + self.io_task_spawner().spawn_blocking(Box::pin(async move { + let res = async move { f(this) }.await; + let _ = tx.send(res); + })); + + async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } + } /// Executes a blocking task on the tracing pool. /// @@ -23,7 +45,16 @@ pub trait SpawnBlocking { /// . fn spawn_tracing(&self, f: F) -> impl Future> where - Self: Sized, + Self: Sized + Clone + Send + Sync + 'static, F: FnOnce(Self) -> EthResult + Send + 'static, - R: Send + 'static; + R: Send + 'static, + { + let this = self.clone(); + async move { + self.tracing_task_pool() + .spawn(move || f(this)) + .await + .map_err(|_| EthApiError::InternalBlockingTaskError)? + } + } } From ecb67712523168a706ecd408c4a02aae8b5574ac Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 02:11:51 +0200 Subject: [PATCH 16/33] Update docs --- crates/rpc/rpc/src/eth/api/traits/blocking_task.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 31779d4c5660..69d656a88a6a 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -1,4 +1,5 @@ -//! Spawns a blocking task. Should be used for long-lived database reads. +//! Spawns a blocking task. CPU heavy tasks are executed with the `rayon` library. IO heavy tasks +//! are executed on the `tokio`` runtime. use futures::Future; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; @@ -15,7 +16,7 @@ pub trait SpawnBlocking { /// Returns a handle for spawning CPU heavy blocking tasks. /// - /// Runtime access in default trait method implementations. + /// Thread pool access in default trait method implementations. fn tracing_task_pool(&self) -> &BlockingTaskPool; /// Executes the future on a new blocking task. From fe494dc756bbb74c8cd28b76879f87c0dd89b76d Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 02:23:38 +0200 Subject: [PATCH 17/33] Revert unrelated changes --- crates/evm/execution-types/src/bundle.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/evm/execution-types/src/bundle.rs b/crates/evm/execution-types/src/bundle.rs index b8f5d1eb4119..10be00a51d8b 100644 --- a/crates/evm/execution-types/src/bundle.rs +++ b/crates/evm/execution-types/src/bundle.rs @@ -50,7 +50,7 @@ impl From for BatchBlockExecutionOutput { pub type BundleStateInit = HashMap, Option, HashMap)>; -/// Types used inside RevertsInit to initialize revms reverts. +/// Types used inside `RevertsInit` to initialize revms reverts. pub type AccountRevertInit = (Option>, Vec); /// Type used to initialize revms reverts. @@ -120,7 +120,7 @@ impl BundleStateWithReceipts { self.bundle.state().iter().map(|(a, acc)| (*a, acc.info.as_ref())) } - /// Return iterator over all [BundleAccount]s in the bundle + /// Return iterator over all [`BundleAccount`]s in the bundle pub fn bundle_accounts_iter(&self) -> impl Iterator { self.bundle.state().iter().map(|(a, acc)| (*a, acc)) } @@ -132,7 +132,7 @@ impl BundleStateWithReceipts { /// Get storage if value is known. /// - /// This means that depending on status we can potentially return U256::ZERO. + /// This means that depending on status we can potentially return `U256::ZERO`. pub fn storage(&self, address: &Address, storage_key: U256) -> Option { self.bundle.account(address).and_then(|a| a.storage_slot(storage_key)) } @@ -142,8 +142,8 @@ impl BundleStateWithReceipts { self.bundle.bytecode(code_hash).map(Bytecode) } - /// Returns [HashedPostState] for this bundle state. - /// See [HashedPostState::from_bundle_state] for more info. + /// Returns [`HashedPostState`] for this bundle state. + /// See [`HashedPostState::from_bundle_state`] for more info. pub fn hash_state_slow(&self) -> HashedPostState { HashedPostState::from_bundle_state(&self.bundle.state) } @@ -174,8 +174,11 @@ impl BundleStateWithReceipts { /// Returns the receipt root for all recorded receipts. /// Note: this function calculated Bloom filters for every receipt and created merkle trees /// of receipt. This is a expensive operation. - pub fn receipts_root_slow(&self, block_number: BlockNumber) -> Option { - self.receipts.root_slow(self.block_number_to_index(block_number)?) + pub fn receipts_root_slow(&self, _block_number: BlockNumber) -> Option { + #[cfg(feature = "optimism")] + panic!("This should not be called in optimism mode. Use `optimism_receipts_root_slow` instead."); + #[cfg(not(feature = "optimism"))] + self.receipts.root_slow(self.block_number_to_index(_block_number)?) } /// Returns the receipt root for all recorded receipts. @@ -285,7 +288,7 @@ impl BundleStateWithReceipts { self.receipts.extend(other.receipts.receipt_vec); } - /// Prepends present the state with the given BundleState. + /// Prepends present the state with the given `BundleState`. /// It adds changes from the given state but does not override any existing changes. /// /// Reverts and receipts are not updated. From 8b8ed167b6b1d8f4e3298394410627b80e776958 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 12:03:03 +0200 Subject: [PATCH 18/33] Fix lint --- Cargo.lock | 2 +- crates/optimism/rpc/src/transaction.rs | 2 +- crates/rpc/rpc/src/eth/api/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/blocking_task.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 467ae51d06dd..5b1b5a9030b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7385,7 +7385,7 @@ version = "0.2.0-beta.8" [[package]] name = "reth-optimism-rpc" -version = "0.2.0-beta.7" +version = "0.2.0-beta.8" dependencies = [ "futures", "jsonrpsee", diff --git a/crates/optimism/rpc/src/transaction.rs b/crates/optimism/rpc/src/transaction.rs index 32b2efcd96ed..e6f57a02c556 100644 --- a/crates/optimism/rpc/src/transaction.rs +++ b/crates/optimism/rpc/src/transaction.rs @@ -20,7 +20,7 @@ pub struct OptimismTxMeta { } impl OptimismTxMeta { - /// Creates a new [OptimismTxMeta]. + /// Creates a new [`OptimismTxMeta`]. pub const fn new( l1_block_info: Option, l1_fee: Option, diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 533e35741f94..3990492dea85 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -430,7 +430,7 @@ where } } -/// The default gas limit for eth_call and adjacent calls. +/// The default gas limit for `eth_call` and adjacent calls. /// /// This is different from the default to regular 30M block gas limit /// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow for diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 69d656a88a6a..d0808f4d8ea1 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -1,5 +1,5 @@ //! Spawns a blocking task. CPU heavy tasks are executed with the `rayon` library. IO heavy tasks -//! are executed on the `tokio`` runtime. +//! are executed on the `tokio` runtime. use futures::Future; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; From f3ed6bd8120db59436f24b9953ab5bcc1c8c1fec Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 12:08:56 +0200 Subject: [PATCH 19/33] Add super traits to spawn blocking --- crates/rpc/rpc/src/eth/api/traits/blocking_task.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index d0808f4d8ea1..b508f1b846b2 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -8,7 +8,7 @@ use tokio::sync::oneshot; use crate::eth::error::{EthApiError, EthResult}; /// Executes code on a blocking thread. -pub trait SpawnBlocking { +pub trait SpawnBlocking: Clone + Send + Sync + 'static { /// Returns a handle for spawning IO heavy blocking tasks. /// /// Runtime access in default trait method implementations. @@ -25,7 +25,6 @@ pub trait SpawnBlocking { /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where - Self: Sized + Clone + Send + Sync + 'static, F: FnOnce(Self) -> EthResult + Send + 'static, R: Send + 'static, { @@ -46,7 +45,6 @@ pub trait SpawnBlocking { /// . fn spawn_tracing(&self, f: F) -> impl Future> where - Self: Sized + Clone + Send + Sync + 'static, F: FnOnce(Self) -> EthResult + Send + 'static, R: Send + 'static, { From 16334cdeda13792706065a0a1aa9effc2d170b54 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 12:25:47 +0200 Subject: [PATCH 20/33] Move impl of methods using evm config to default trait methods --- crates/rpc/rpc/src/eth/api/mod.rs | 6 ++ .../rpc/rpc/src/eth/api/traits/transaction.rs | 47 +++++++++-- crates/rpc/rpc/src/eth/api/transactions.rs | 83 ++----------------- 3 files changed, 54 insertions(+), 82 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 3990492dea85..231486e9299b 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -516,4 +516,10 @@ impl EthApiInner &BlockingTaskPool { &self.blocking_task_pool } + + /// Returns a handle to the EVM config. + #[inline] + pub const fn evm_config(&self) -> &EvmConfig { + &self.evm_config + } } diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 399bb6b46429..e434e53fe4ba 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -6,6 +6,7 @@ use crate::eth::{ revm_utils::EvmOverrides, TransactionSource, }; +use reth_evm::ConfigureEvm; use reth_primitives::{ BlockId, Bytes, Header, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, B256, @@ -61,6 +62,11 @@ pub trait EthTransactions: Send + Sync { /// Data access in default (L1) trait method implementations. fn provider(&self) -> &impl BlockReaderIdExt; + /// Returns a handle for reading evm config. + /// + /// Data access in default (L1) trait method implementations. + fn evm_config(&self) -> &impl ConfigureEvm; + /// Executes the [EnvWithHandlerCfg] against the given [Database] without committing state /// changes. fn transact( @@ -70,8 +76,13 @@ pub trait EthTransactions: Send + Sync { ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> where DB: Database, - ::Error: Into; - + ::Error: Into, + { + let mut evm = self.evm_config().evm_with_env(db, env); + let res = evm.transact()?; + let (_, env) = evm.into_db_and_env_with_handler_cfg(); + Ok((res, env)) + } /// Executes the [EnvWithHandlerCfg] against the given [Database] without committing state /// changes. fn inspect( @@ -83,7 +94,10 @@ pub trait EthTransactions: Send + Sync { where DB: Database, ::Error: Into, - I: GetInspector; + I: GetInspector, + { + self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env)) + } /// Same as [Self::inspect] but also returns the database again. /// @@ -99,7 +113,13 @@ pub trait EthTransactions: Send + Sync { where DB: Database, ::Error: Into, - I: GetInspector; + I: GetInspector, + { + let mut evm = self.evm_config().evm_with_env_and_inspector(db, env, inspector); + let res = evm.transact()?; + let (db, env) = evm.into_db_and_env_with_handler_cfg(); + Ok((res, env, db)) + } /// Replays all the transactions until the target transaction is found. /// @@ -120,7 +140,24 @@ pub trait EthTransactions: Send + Sync { DB: DatabaseRef, EthApiError: From<::Error>, I: IntoIterator, - Tx: FillableTransaction; + Tx: FillableTransaction, + { + let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); + + let mut evm = self.evm_config().evm_with_env(db, env); + let mut index = 0; + for tx in transactions { + if tx.hash() == target_tx_hash { + // reached the target transaction + break + } + + tx.try_fill_tx_env(evm.tx_mut())?; + evm.transact_commit()?; + index += 1; + } + Ok(index) + } /// Returns default gas limit to use for `eth_call` and tracing RPC methods. fn call_gas_limit(&self) -> u64; diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index a09b9795e6b8..6b34e74fe591 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -40,7 +40,7 @@ use revm::{ db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState, SpecId, }, - GetInspector, Inspector, + Inspector, }; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; @@ -48,7 +48,6 @@ use crate::eth::{ api::{BuildReceipt, EthTransactions, StateCacheDB}, revm_utils::FillableTransaction, }; -use revm_primitives::db::{Database, DatabaseRef}; #[async_trait] impl EthTransactions @@ -66,87 +65,17 @@ where Network: NetworkInfo + 'static, EvmConfig: ConfigureEvm, { + #[inline] fn provider(&self) -> &impl BlockReaderIdExt { &self.inner.provider } - fn transact( - &self, - db: DB, - env: EnvWithHandlerCfg, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into, - { - let mut evm = self.inner.evm_config.evm_with_env(db, env); - let res = evm.transact()?; - let (_, env) = evm.into_db_and_env_with_handler_cfg(); - Ok((res, env)) - } - - fn inspect( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into, - I: GetInspector, - { - self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env)) - } - - fn inspect_and_return_db( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg, DB)> - where - DB: Database, - ::Error: Into, - I: GetInspector, - { - let mut evm = self.inner.evm_config.evm_with_env_and_inspector(db, env, inspector); - let res = evm.transact()?; - let (db, env) = evm.into_db_and_env_with_handler_cfg(); - Ok((res, env, db)) - } - - fn replay_transactions_until( - &self, - db: &mut CacheDB, - cfg: CfgEnvWithHandlerCfg, - block_env: BlockEnv, - transactions: I, - target_tx_hash: B256, - ) -> Result - where - DB: DatabaseRef, - EthApiError: From<::Error>, - I: IntoIterator, - Tx: FillableTransaction, - { - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); - - let mut evm = self.inner.evm_config.evm_with_env(db, env); - let mut index = 0; - for tx in transactions { - if tx.hash() == target_tx_hash { - // reached the target transaction - break - } - - tx.try_fill_tx_env(evm.tx_mut())?; - evm.transact_commit()?; - index += 1; - } - Ok(index) + #[inline] + fn evm_config(&self) -> &impl ConfigureEvm { + &self.inner.evm_config } + #[inline] fn call_gas_limit(&self) -> u64 { self.inner.gas_cap } From 20d248945e2a26fd414c0024fcaf890fb683ab96 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 13:34:19 +0200 Subject: [PATCH 21/33] Move EthApi state access methods into trait --- crates/rpc/rpc/src/debug.rs | 6 +-- crates/rpc/rpc/src/eth/api/call.rs | 11 +++-- crates/rpc/rpc/src/eth/api/mod.rs | 48 ++----------------- crates/rpc/rpc/src/eth/api/state.rs | 15 ++++-- crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 + crates/rpc/rpc/src/eth/api/traits/state.rs | 46 ++++++++++++++++++ .../rpc/rpc/src/eth/api/traits/transaction.rs | 33 +++++++++---- crates/rpc/rpc/src/eth/api/transactions.rs | 42 ++++++++-------- crates/rpc/rpc/src/eth/bundle.rs | 4 +- crates/rpc/rpc/src/otterscan.rs | 7 ++- crates/rpc/rpc/src/trace.rs | 6 +-- 11 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 crates/rpc/rpc/src/eth/api/traits/state.rs diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 1830ae8ad076..b5fc8b7c49d6 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,6 +1,6 @@ use crate::{ eth::{ - api::{traits::SpawnBlocking, EthTransactions}, + api::{traits::SpawnBlocking, EthTransactions, LoadState}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, }, @@ -65,7 +65,7 @@ impl DebugApi { impl DebugApi where Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadState + 'static, { /// Acquires a permit to execute a tracing call. async fn acquire_trace_permit(&self) -> Result { @@ -614,7 +614,7 @@ where impl DebugApiServer for DebugApi where Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthApiSpec + SpawnBlocking + 'static, + Eth: EthApiSpec + SpawnBlocking + LoadState + 'static, { /// Handler for `debug_getRawHeader` async fn raw_header(&self, block_id: BlockId) -> RpcResult { diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index d0fe945972f6..4d20487f233e 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -25,15 +25,17 @@ use reth_rpc_types::{ }; use reth_transaction_pool::TransactionPool; use revm::{ - db::{CacheDB, DatabaseRef}, + db::CacheDB, primitives::{ BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HaltReason, TransactTo, }, - DatabaseCommit, + DatabaseCommit, DatabaseRef, }; use revm_inspectors::access_list::AccessListInspector; use tracing::trace; +use super::LoadState; + // Gas per transaction not creating a contract. const MIN_TRANSACTION_GAS: u64 = 21_000u64; /// Allowed error ratio for gas estimation @@ -43,6 +45,7 @@ const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015; impl EthApi where + Self: LoadState, Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, @@ -59,7 +62,7 @@ where let (cfg, block_env, at) = self.evm_env_at(at).await?; self.spawn_blocking_io(move |this| { - let state = this.state_at(at)?; + let state = this.state_at_block_id(at)?; this.estimate_gas_with(cfg, block_env, request, state, state_override) }) .await @@ -394,7 +397,7 @@ where at: BlockId, mut request: TransactionRequest, ) -> EthResult { - let state = self.state_at(at)?; + let state = self.state_at_block_id(at)?; let mut env = build_call_evm_env(cfg, block, request.clone())?; diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 231486e9299b..4333a4f94fe0 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -7,12 +7,9 @@ use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; use reth_primitives::{ revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Address, BlockId, BlockNumberOrTag, ChainInfo, SealedBlockWithSenders, SealedHeader, B256, - U256, U64, -}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory, + Address, BlockNumberOrTag, ChainInfo, SealedBlockWithSenders, SealedHeader, U256, U64, }; +use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::{SyncInfo, SyncStatus}; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::TransactionPool; @@ -51,7 +48,7 @@ pub mod transactions; use crate::eth::traits::RawTransactionForwarder; pub use receipt::ReceiptBuilder; -pub use traits::{BuildReceipt, EthBlocks, EthTransactions, StateCacheDB}; +pub use traits::{BuildReceipt, EthBlocks, EthTransactions, LoadState, StateCacheDB}; pub use transactions::TransactionSource; /// `Eth` API trait. @@ -203,45 +200,6 @@ where } } -// === State access helpers === - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, -{ - /// Returns the state at the given [`BlockId`] enum. - /// - /// Note: if not [`BlockNumberOrTag::Pending`] then this will only return canonical state. See also - pub fn state_at_block_id(&self, at: BlockId) -> EthResult { - Ok(self.provider().state_by_block_id(at)?) - } - - /// Returns the state at the given [`BlockId`] enum or the latest. - /// - /// Convenience function to interprets `None` as `BlockId::Number(BlockNumberOrTag::Latest)` - pub fn state_at_block_id_or_latest( - &self, - block_id: Option, - ) -> EthResult { - if let Some(block_id) = block_id { - self.state_at_block_id(block_id) - } else { - Ok(self.latest_state()?) - } - } - - /// Returns the state at the given block number - pub fn state_at_hash(&self, block_hash: B256) -> RethResult { - Ok(self.provider().history_by_block_hash(block_hash)?) - } - - /// Returns the _latest_ state - pub fn latest_state(&self) -> RethResult { - Ok(self.provider().latest()?) - } -} - impl EthApi where Provider: diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index d7c1bafacf9f..b370f35aae84 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -6,13 +6,13 @@ use crate::{ }; use reth_evm::ConfigureEvm; use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, U256}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProvider, StateProviderFactory, -}; +use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_transaction_pool::{PoolTransaction, TransactionPool}; +use super::LoadState; + impl EthApi where Provider: @@ -113,6 +113,15 @@ where } } +impl LoadState for EthApi +where + Provider: StateProviderFactory, +{ + fn provider(&self) -> &impl StateProviderFactory { + &self.inner.provider + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index 505f7c106648..7ab1321d3d64 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -3,9 +3,11 @@ pub mod block; pub mod blocking_task; pub mod receipt; +pub mod state; pub mod transaction; pub use block::EthBlocks; pub use blocking_task::SpawnBlocking; pub use receipt::BuildReceipt; +pub use state::LoadState; pub use transaction::{EthTransactions, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/traits/state.rs b/crates/rpc/rpc/src/eth/api/traits/state.rs new file mode 100644 index 000000000000..3148ec2438ca --- /dev/null +++ b/crates/rpc/rpc/src/eth/api/traits/state.rs @@ -0,0 +1,46 @@ +//! Loads state from database. Helper trait for `eth_`transaction and state RPC methods. + +use reth_primitives::{BlockId, B256}; +use reth_provider::{StateProviderBox, StateProviderFactory}; + +use crate::eth::error::EthResult; + +/// Loads state from database. +pub trait LoadState { + /// Returns a handle for reading state from database. + /// + /// Data access in default trait method implementations. + fn provider(&self) -> &impl StateProviderFactory; + + /// Returns the state at the given block number + fn state_at_hash(&self, block_hash: B256) -> EthResult { + Ok(self.provider().history_by_block_hash(block_hash)?) + } + + /// Returns the state at the given [`BlockId`] enum. + /// + /// Note: if not [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this + /// will only return canonical state. See also + fn state_at_block_id(&self, at: BlockId) -> EthResult { + Ok(self.provider().state_by_block_id(at)?) + } + + /// Returns the _latest_ state + fn latest_state(&self) -> EthResult { + Ok(self.provider().latest()?) + } + + /// Returns the state at the given [`BlockId`] enum or the latest. + /// + /// Convenience function to interprets `None` as `BlockId::Number(BlockNumberOrTag::Latest)` + fn state_at_block_id_or_latest( + &self, + block_id: Option, + ) -> EthResult { + if let Some(block_id) = block_id { + self.state_at_block_id(block_id) + } else { + Ok(self.latest_state()?) + } + } +} diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index e434e53fe4ba..41d25c4d12d6 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -27,7 +27,7 @@ use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use crate::eth::{api::BuildReceipt, revm_utils::FillableTransaction}; use revm_primitives::db::{Database, DatabaseRef}; -use super::SpawnBlocking; +use super::{LoadState, SpawnBlocking}; /// Helper alias type for the state's [`CacheDB`] pub type StateCacheDB = CacheDB>; @@ -162,17 +162,20 @@ pub trait EthTransactions: Send + Sync { /// Returns default gas limit to use for `eth_call` and tracing RPC methods. fn call_gas_limit(&self) -> u64; - /// Returns the state at the given [BlockId] - fn state_at(&self, at: BlockId) -> EthResult; - /// Executes the closure with the state that corresponds to the given [BlockId]. fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult where - F: FnOnce(StateProviderBox) -> EthResult; + Self: LoadState, + F: FnOnce(StateProviderBox) -> EthResult, + { + let state = self.state_at_block_id(at)?; + f(state) + } /// Executes the closure with the state that corresponds to the given [BlockId] on a new task async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult where + Self: LoadState, F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, T: Send + 'static; @@ -182,8 +185,9 @@ pub trait EthTransactions: Send + Sync { /// for. /// If the [BlockId] is pending, this will return the "Pending" tag, otherwise this returns the /// hash of the exact block. - async fn evm_env_at(&self, at: BlockId) - -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)>; + async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> + where + Self: LoadState; /// Returns the revm evm env for the raw block header /// @@ -319,6 +323,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(&mut StateCacheDB, EnvWithHandlerCfg) -> EthResult + Send + 'static, R: Send + 'static; @@ -328,7 +333,9 @@ pub trait EthTransactions: Send + Sync { request: TransactionRequest, at: BlockId, overrides: EvmOverrides, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)>; + ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + where + Self: LoadState; /// Executes the call request at the given [BlockId] on a new task and returns the result of the /// inspect call. @@ -340,6 +347,7 @@ pub trait EthTransactions: Send + Sync { inspector: I, ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> where + Self: LoadState, I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static; /// Executes the transaction on top of the given [BlockId] with a tracer configured by the @@ -357,6 +365,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(TracingInspector, ResultAndState) -> EthResult; /// Same as [Self::trace_at] but also provides the used database to the callback. @@ -374,6 +383,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, R: Send + 'static; @@ -399,6 +409,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult> where + Self: LoadState, F: FnOnce(TransactionInfo, TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, @@ -419,6 +430,7 @@ pub trait EthTransactions: Send + Sync { /// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool). async fn spawn_replay_transaction(&self, hash: B256, f: F) -> EthResult> where + Self: LoadState, F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, R: Send + 'static; @@ -438,6 +450,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult> where + Self: LoadState, F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, @@ -461,6 +474,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult>> where + Self: LoadState, // This is the callback that's invoked for each transaction with the inspector, the result, // state and db F: for<'a> Fn( @@ -498,6 +512,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult>> where + Self: LoadState, // This is the callback that's invoked for each transaction with the inspector, the result, // state and db F: for<'a> Fn( @@ -529,6 +544,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult>> where + Self: LoadState, F: for<'a> Fn( TransactionInfo, TracingInspector, @@ -567,6 +583,7 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult>> where + Self: LoadState, F: for<'a> Fn( TransactionInfo, Insp, diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 6b34e74fe591..2a61db8fa09f 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -49,6 +49,8 @@ use crate::eth::{ revm_utils::FillableTransaction, }; +use super::LoadState; + #[async_trait] impl EthTransactions for EthApi @@ -80,34 +82,23 @@ where self.inner.gas_cap } - fn state_at(&self, at: BlockId) -> EthResult { - self.state_at_block_id(at) - } - - fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - F: FnOnce(StateProviderBox) -> EthResult, - { - let state = self.state_at(at)?; - f(state) - } - async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult where + Self: LoadState, F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, T: Send + 'static, { self.spawn_tracing(move |this| { - let state = this.state_at(at)?; + let state = this.state_at_block_id(at)?; f(state) }) .await } - async fn evm_env_at( - &self, - at: BlockId, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> { + async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> + where + Self: LoadState, + { if at.is_pending() { let PendingBlockEnv { cfg, block_env, origin } = self.pending_block_env_and_cfg()?; Ok((cfg, block_env, origin.state_block_id())) @@ -495,6 +486,7 @@ where f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(&mut StateCacheDB, EnvWithHandlerCfg) -> EthResult + Send + 'static, R: Send + 'static, { @@ -503,7 +495,7 @@ where self.inner .blocking_task_pool .spawn(move || { - let state = this.state_at(at)?; + let state = this.state_at_block_id(at)?; let mut db = CacheDB::new(StateProviderDatabase::new(state)); let env = prepare_call_env( @@ -525,7 +517,10 @@ where request: TransactionRequest, at: BlockId, overrides: EvmOverrides, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> { + ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + where + Self: LoadState, + { let this = self.clone(); self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env)).await } @@ -538,6 +533,7 @@ where inspector: I, ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> where + Self: LoadState, I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, { let this = self.clone(); @@ -555,6 +551,7 @@ where f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(TracingInspector, ResultAndState) -> EthResult, { let this = self.clone(); @@ -574,6 +571,7 @@ where f: F, ) -> EthResult where + Self: LoadState, F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, R: Send + 'static, { @@ -607,6 +605,7 @@ where async fn spawn_replay_transaction(&self, hash: B256, f: F) -> EthResult> where + Self: LoadState, F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, R: Send + 'static, { @@ -653,6 +652,7 @@ where f: F, ) -> EthResult> where + Self: LoadState, F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, @@ -703,6 +703,7 @@ where f: F, ) -> EthResult>> where + Self: LoadState, F: for<'a> Fn( TransactionInfo, Insp, @@ -761,7 +762,7 @@ where .peekable(); // now get the state - let state = this.state_at(state_at.into())?; + let state = this.state_at_block_id(state_at.into())?; let mut db = CacheDB::new(StateProviderDatabase::new(state)); while let Some((tx_info, tx)) = transactions.next() { @@ -790,6 +791,7 @@ where impl BuildReceipt for EthApi { + #[inline] fn cache(&self) -> &EthStateCache { &self.inner.eth_cache } diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 4ccec5d4e06b..2915a6c9779f 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -24,6 +24,8 @@ use revm::{ use revm_primitives::{EnvWithHandlerCfg, MAX_BLOB_GAS_PER_BLOCK}; use std::sync::Arc; +use super::api::LoadState; + /// `Eth` bundle implementation. pub struct EthBundle { /// All nested fields bundled together. @@ -39,7 +41,7 @@ impl EthBundle { impl EthBundle where - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadState + '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 diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 3945504dd596..064ff9f14ea0 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -14,7 +14,10 @@ use reth_rpc_types::{ BlockTransactions, Transaction, }; -use crate::{eth::api::EthTransactions, result::internal_rpc_err}; +use crate::{ + eth::api::{EthTransactions, LoadState}, + result::internal_rpc_err, +}; const API_LEVEL: u64 = 8; @@ -34,7 +37,7 @@ impl OtterscanApi { #[async_trait] impl OtterscanServer for OtterscanApi where - Eth: EthApiServer + EthTransactions, + Eth: EthApiServer + EthTransactions + LoadState, { /// Handler for `ots_hasCode` async fn has_code(&self, address: Address, block_number: Option) -> RpcResult { diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index c0d72df1430f..3b1cb4019b86 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,5 +1,5 @@ use crate::eth::{ - api::EthTransactions, + api::{EthTransactions, LoadState}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, utils::recover_raw_transaction, @@ -72,7 +72,7 @@ impl TraceApi { impl TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadState + 'static, { /// Executes the given call and returns a number of possible traces for it. pub async fn trace_call(&self, trace_request: TraceCallRequest) -> EthResult { @@ -485,7 +485,7 @@ where impl TraceApiServer for TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadState + 'static, { /// Executes the given call and returns a number of possible traces for it. /// From 4a400323f70c4755903e45e3b8fe926669b93de2 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 17:28:58 +0200 Subject: [PATCH 22/33] Move EthTransaction impls to default trait methods --- crates/rpc/rpc/src/eth/api/mod.rs | 12 + crates/rpc/rpc/src/eth/api/state.rs | 29 +-- .../rpc/rpc/src/eth/api/traits/transaction.rs | 221 ++++++++++++++++-- crates/rpc/rpc/src/eth/api/transactions.rs | 212 +++-------------- 4 files changed, 250 insertions(+), 224 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 4333a4f94fe0..8baa17e6f410 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -480,4 +480,16 @@ impl EthApiInner &EvmConfig { &self.evm_config } + + /// Returns a handle to the transaction pool. + #[inline] + pub const fn pool(&self) -> &Pool { + &self.pool + } + + /// Returns a handle to the transaction forwarder. + #[inline] + pub const fn raw_tx_forwarder(&self) -> &Option> { + &self.raw_transaction_forwarder + } } diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index b370f35aae84..a5d79965f328 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -1,7 +1,7 @@ //! Contains RPC handler implementations specific to state. use crate::{ - eth::error::{EthApiError, EthResult, RpcInvalidTransactionError}, + eth::error::{EthApiError, EthResult}, EthApi, }; use reth_evm::ConfigureEvm; @@ -9,7 +9,7 @@ use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, U256}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; use reth_rpc_types_compat::proof::from_primitive_account_proof; -use reth_transaction_pool::{PoolTransaction, TransactionPool}; +use reth_transaction_pool::TransactionPool; use super::LoadState; @@ -36,31 +36,6 @@ where .unwrap_or_default()) } - /// Returns the number of transactions sent from an address at the given block identifier. - /// - /// If this is [`BlockNumberOrTag::Pending`] then this will look up the highest transaction in - /// pool and return the next nonce (highest + 1). - pub(crate) fn get_transaction_count( - &self, - address: Address, - block_id: Option, - ) -> EthResult { - if block_id == Some(BlockId::pending()) { - let address_txs = self.pool().get_transactions_by_sender(address); - if let Some(highest_nonce) = - address_txs.iter().map(|item| item.transaction.nonce()).max() - { - let tx_count = highest_nonce - .checked_add(1) - .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; - return Ok(U256::from(tx_count)) - } - } - - let state = self.state_at_block_id_or_latest(block_id)?; - Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) - } - pub(crate) fn storage_at( &self, address: Address, diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 41d25c4d12d6..279a3b75f671 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -1,19 +1,18 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. -use crate::eth::{ - error::{EthApiError, EthResult}, - revm_utils::EvmOverrides, - TransactionSource, -}; +use std::sync::Arc; + use reth_evm::ConfigureEvm; use reth_primitives::{ - BlockId, Bytes, Header, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta, - TransactionSigned, TxHash, B256, + revm::env::fill_block_env_with_coinbase, Address, BlockId, Bytes, + FromRecoveredPooledTransaction, Header, IntoRecoveredTransaction, Receipt, SealedBlock, + SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, B256, U256, }; use reth_provider::{BlockReaderIdExt, ReceiptProvider, StateProviderBox, TransactionsProvider}; use reth_revm::database::StateProviderDatabase; use reth_rpc_types::{AnyTransactionReceipt, TransactionInfo, TransactionRequest}; +use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; use revm::{ db::CacheDB, primitives::{ @@ -23,11 +22,23 @@ use revm::{ GetInspector, Inspector, }; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; +use revm_primitives::{ + db::{Database, DatabaseRef}, + SpecId, +}; -use crate::eth::{api::BuildReceipt, revm_utils::FillableTransaction}; -use revm_primitives::db::{Database, DatabaseRef}; - -use super::{LoadState, SpawnBlocking}; +use crate::{ + eth::{ + api::{BuildReceipt, LoadState, SpawnBlocking}, + cache::EthStateCache, + error::{EthApiError, EthResult, RpcInvalidTransactionError}, + revm_utils::{EvmOverrides, FillableTransaction}, + traits::RawTransactionForwarder, + utils::recover_raw_transaction, + TransactionSource, + }, + EthApiSpec, +}; /// Helper alias type for the state's [`CacheDB`] pub type StateCacheDB = CacheDB>; @@ -57,11 +68,29 @@ pub type StateCacheDB = CacheDB>; /// This implementation follows the behaviour of Geth and disables the basefee check for tracing. #[async_trait::async_trait] pub trait EthTransactions: Send + Sync { + /// Transaction pool with pending transactions. + type Pool: TransactionPool; + /// Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. fn provider(&self) -> &impl BlockReaderIdExt; + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Returns a handle for reading data from pool. + /// + /// Data access in default (L1) trait method implementations. + fn pool(&self) -> &Self::Pool; + + /// Returns a handle for forwarding received raw transactions. + /// + /// Access to transaction forwarder in default (L1) trait method implementations. + fn raw_tx_forwarder(&self) -> &Option>; + /// Returns a handle for reading evm config. /// /// Data access in default (L1) trait method implementations. @@ -194,14 +223,29 @@ pub trait EthTransactions: Send + Sync { /// This is used for tracing raw blocks async fn evm_env_for_raw_block( &self, - at: &Header, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)>; + header: &Header, + ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)> + where + Self: LoadState, + { + // get the parent config first + let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; + + let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; + fill_block_env_with_coinbase(&mut block_env, header, after_merge, header.beneficiary); + + Ok((cfg, block_env)) + } /// Get all transactions in the block with the given hash. /// /// Returns `None` if block does not exist. - async fn transactions_by_block(&self, block: B256) - -> EthResult>>; + async fn transactions_by_block( + &self, + block: B256, + ) -> EthResult>> { + Ok(self.cache().get_block_transactions(block).await?) + } /// Get the entire block for the given id. /// @@ -233,7 +277,20 @@ pub trait EthTransactions: Send + Sync { /// Returns `Ok(None)` if no matching transaction was found. async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> where - Self: SpawnBlocking; + Self: SpawnBlocking, + { + // Note: this is mostly used to fetch pooled transactions so we check the pool first + if let Some(tx) = + self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded()) + { + return Ok(Some(tx)) + } + + self.spawn_blocking_io(move |this| { + Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) + }) + .await + } /// Returns the transaction by hash. /// @@ -242,21 +299,97 @@ pub trait EthTransactions: Send + Sync { /// Returns `Ok(None)` if no matching transaction was found. async fn transaction_by_hash(&self, hash: B256) -> EthResult> where - Self: SpawnBlocking; + Self: SpawnBlocking, + { + // Try to find the transaction on disk + let mut resp = self + .spawn_blocking_io(move |this| { + match this.provider().transaction_by_hash_with_meta(hash)? { + None => Ok(None), + Some((tx, meta)) => { + // Note: we assume this transaction is valid, because it's mined (or part of + // pending block) and already. We don't need to + // check for pre EIP-2 because this transaction could be pre-EIP-2. + let transaction = tx + .into_ecrecovered_unchecked() + .ok_or(EthApiError::InvalidTransactionSignature)?; + + let tx = TransactionSource::Block { + transaction, + index: meta.index, + block_hash: meta.block_hash, + block_number: meta.block_number, + base_fee: meta.base_fee, + }; + Ok(Some(tx)) + } + } + }) + .await?; + + if resp.is_none() { + // tx not found on disk, check pool + if let Some(tx) = + self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction()) + { + resp = Some(TransactionSource::Pool(tx)); + } + } + + Ok(resp) + } /// Returns the transaction by including its corresponding [BlockId] /// /// Note: this supports pending transactions async fn transaction_by_hash_at( &self, - hash: B256, - ) -> EthResult>; + transaction_hash: B256, + ) -> EthResult> + where + Self: SpawnBlocking, + { + match self.transaction_by_hash(transaction_hash).await? { + None => return Ok(None), + Some(tx) => { + let res = match tx { + tx @ TransactionSource::Pool(_) => (tx, BlockId::pending()), + TransactionSource::Block { + transaction, + index, + block_hash, + block_number, + base_fee, + } => { + let at = BlockId::Hash(block_hash.into()); + let tx = TransactionSource::Block { + transaction, + index, + block_hash, + block_number, + base_fee, + }; + (tx, at) + } + }; + Ok(Some(res)) + } + } + } /// Returns the _historical_ transaction and the block it was mined in async fn historical_transaction_by_hash_at( &self, hash: B256, - ) -> EthResult>; + ) -> EthResult> + where + Self: SpawnBlocking, + { + match self.transaction_by_hash_at(hash).await? { + None => Ok(None), + Some((tx, at)) => Ok(at.as_block_hash().map(|hash| (tx, hash))), + } + } /// Returns the transaction receipt for the given hash. /// @@ -304,11 +437,55 @@ pub trait EthTransactions: Send + Sync { /// Decodes and recovers the transaction and submits it to the pool. /// /// Returns the hash of the transaction. - async fn send_raw_transaction(&self, tx: Bytes) -> EthResult; + async fn send_raw_transaction(&self, tx: Bytes) -> EthResult { + // On optimism, transactions are forwarded directly to the sequencer to be included in + // blocks that it builds. + if let Some(client) = self.raw_tx_forwarder().as_ref() { + tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); + client.forward_raw_transaction(&tx).await?; + } + + let recovered = recover_raw_transaction(tx)?; + let pool_transaction = + ::Transaction::from_recovered_pooled_transaction( + recovered, + ); + + // submit the transaction to the pool with a `Local` origin + let hash = self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; + + Ok(hash) + } /// Signs transaction with a matching signer, if any and submits the transaction to the pool. /// Returns the hash of the signed transaction. - async fn send_transaction(&self, request: TransactionRequest) -> EthResult; + async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult + where + Self: EthApiSpec + LoadState; + + /// Returns the number of transactions sent from an address at the given block identifier. + /// + /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will + /// look up the highest transaction in pool and return the next nonce (highest + 1). + fn get_transaction_count(&self, address: Address, block_id: Option) -> EthResult + where + Self: LoadState, + { + if block_id == Some(BlockId::pending()) { + let address_txs = self.pool().get_transactions_by_sender(address); + if let Some(highest_nonce) = + address_txs.iter().map(|item| item.transaction.nonce()).max() + { + let tx_count = highest_nonce + .checked_add(1) + .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; + return Ok(U256::from(tx_count)) + } + } + + let state = self.state_at_block_id_or_latest(block_id)?; + Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) + } /// Prepares the state and env for the given [TransactionRequest] at the given [BlockId] and /// executes the closure on a new task returning the result of the closure. diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 2a61db8fa09f..a2931ee0572b 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -1,22 +1,14 @@ //! Contains RPC handler implementations specific to transactions -use crate::{ - eth::{ - api::{pending_block::PendingBlockEnv, SpawnBlocking}, - cache::EthStateCache, - error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, - revm_utils::{prepare_call_env, EvmOverrides}, - utils::recover_raw_transaction, - }, - EthApi, EthApiSpec, -}; + +use std::sync::Arc; + use alloy_primitives::TxKind as RpcTransactionKind; use async_trait::async_trait; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; use reth_primitives::{ - revm::env::{fill_block_env_with_coinbase, tx_env_with_recovered}, - Address, BlockId, BlockNumberOrTag, Bytes, FromRecoveredPooledTransaction, Header, - IntoRecoveredTransaction, SealedBlock, SealedBlockWithSenders, TransactionSigned, + revm::env::tx_env_with_recovered, Address, BlockId, BlockNumberOrTag, Bytes, + FromRecoveredPooledTransaction, SealedBlock, SealedBlockWithSenders, TransactionSigned, TransactionSignedEcRecovered, B256, U256, }; use reth_provider::{ @@ -29,8 +21,7 @@ use reth_rpc_types::{ EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest, LegacyTransactionRequest, }, - AnyTransactionReceipt, Index, Transaction, TransactionInfo, TransactionRequest, - TypedTransactionRequest, + Index, Transaction, TransactionInfo, TransactionRequest, TypedTransactionRequest, }; use reth_rpc_types_compat::transaction::from_recovered_with_block_context; use reth_transaction_pool::{TransactionOrigin, TransactionPool}; @@ -38,19 +29,25 @@ use revm::{ db::CacheDB, primitives::{ db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, - ExecutionResult, ResultAndState, SpecId, + ExecutionResult, ResultAndState, }, Inspector, }; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; -use crate::eth::{ - api::{BuildReceipt, EthTransactions, StateCacheDB}, - revm_utils::FillableTransaction, +use crate::{ + eth::{ + api::{ + pending_block::PendingBlockEnv, BuildReceipt, EthTransactions, LoadState, + SpawnBlocking, StateCacheDB, + }, + cache::EthStateCache, + error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, + revm_utils::{prepare_call_env, EvmOverrides, FillableTransaction}, + }, + EthApi, EthApiSpec, }; -use super::LoadState; - #[async_trait] impl EthTransactions for EthApi @@ -67,14 +64,31 @@ where Network: NetworkInfo + 'static, EvmConfig: ConfigureEvm, { + type Pool = Pool; + #[inline] fn provider(&self) -> &impl BlockReaderIdExt { - &self.inner.provider + self.inner.provider() + } + + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() } #[inline] fn evm_config(&self) -> &impl ConfigureEvm { - &self.inner.evm_config + self.inner.evm_config() + } + + #[inline] + fn pool(&self) -> &Self::Pool { + self.inner.pool() + } + + #[inline] + fn raw_tx_forwarder(&self) -> &Option> { + self.inner.raw_tx_forwarder() } #[inline] @@ -113,26 +127,6 @@ where } } - async fn evm_env_for_raw_block( - &self, - header: &Header, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)> { - // get the parent config first - let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; - - let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; - fill_block_env_with_coinbase(&mut block_env, header, after_merge, header.beneficiary); - - Ok((cfg, block_env)) - } - - async fn transactions_by_block( - &self, - block: B256, - ) -> EthResult>> { - Ok(self.cache().get_block_transactions(block).await?) - } - async fn block_by_id(&self, id: BlockId) -> EthResult> { self.block(id).await } @@ -151,138 +145,6 @@ where self.block_by_id(block).await.map(|block| block.map(|block| block.body)) } - async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> - where - Self: SpawnBlocking, - { - // Note: this is mostly used to fetch pooled transactions so we check the pool first - if let Some(tx) = - self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded()) - { - return Ok(Some(tx)) - } - - self.spawn_blocking_io(move |this| { - Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) - }) - .await - } - - async fn transaction_by_hash(&self, hash: B256) -> EthResult> - where - Self: SpawnBlocking, - { - // Try to find the transaction on disk - let mut resp = self - .spawn_blocking_io(move |this| { - match this.provider().transaction_by_hash_with_meta(hash)? { - None => Ok(None), - Some((tx, meta)) => { - // Note: we assume this transaction is valid, because it's mined (or part of - // pending block) and already. We don't need to - // check for pre EIP-2 because this transaction could be pre-EIP-2. - let transaction = tx - .into_ecrecovered_unchecked() - .ok_or(EthApiError::InvalidTransactionSignature)?; - - let tx = TransactionSource::Block { - transaction, - index: meta.index, - block_hash: meta.block_hash, - block_number: meta.block_number, - base_fee: meta.base_fee, - }; - Ok(Some(tx)) - } - } - }) - .await?; - - if resp.is_none() { - // tx not found on disk, check pool - if let Some(tx) = - self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction()) - { - resp = Some(TransactionSource::Pool(tx)); - } - } - - Ok(resp) - } - - async fn transaction_by_hash_at( - &self, - transaction_hash: B256, - ) -> EthResult> { - match self.transaction_by_hash(transaction_hash).await? { - None => return Ok(None), - Some(tx) => { - let res = match tx { - tx @ TransactionSource::Pool(_) => (tx, BlockId::pending()), - TransactionSource::Block { - transaction, - index, - block_hash, - block_number, - base_fee, - } => { - let at = BlockId::Hash(block_hash.into()); - let tx = TransactionSource::Block { - transaction, - index, - block_hash, - block_number, - base_fee, - }; - (tx, at) - } - }; - Ok(Some(res)) - } - } - } - - async fn historical_transaction_by_hash_at( - &self, - hash: B256, - ) -> EthResult> { - match self.transaction_by_hash_at(hash).await? { - None => Ok(None), - Some((tx, at)) => Ok(at.as_block_hash().map(|hash| (tx, hash))), - } - } - - async fn transaction_receipt(&self, hash: B256) -> EthResult> - where - Self: BuildReceipt + SpawnBlocking + Clone + Send + 'static, - { - let result = self.load_transaction_and_receipt(hash).await?; - - let (tx, meta, receipt) = match result { - Some((tx, meta, receipt)) => (tx, meta, receipt), - None => return Ok(None), - }; - - self.build_transaction_receipt(tx, meta, receipt).await.map(Some) - } - - async fn send_raw_transaction(&self, tx: Bytes) -> EthResult { - // On optimism, transactions are forwarded directly to the sequencer to be included in - // blocks that it builds. - if let Some(client) = self.inner.raw_transaction_forwarder.as_ref() { - tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); - client.forward_raw_transaction(&tx).await?; - } - - let recovered = recover_raw_transaction(tx)?; - let pool_transaction = ::from_recovered_pooled_transaction(recovered); - - // submit the transaction to the pool with a `Local` origin - let hash = self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; - - Ok(hash) - } - async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult { let from = match request.from { Some(from) => from, From f2df91565f04dfb612278109c045b34f2bfc30ee Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 20:25:36 +0200 Subject: [PATCH 23/33] Move state rpc methods into new trait default impl --- crates/rpc/rpc/src/eth/api/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/server.rs | 24 +--- crates/rpc/rpc/src/eth/api/state.rs | 89 +------------ .../rpc/src/eth/api/traits/blocking_task.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/state.rs | 126 +++++++++++++++++- .../rpc/rpc/src/eth/api/traits/transaction.rs | 41 ++---- crates/rpc/rpc/src/eth/api/transactions.rs | 9 +- 8 files changed, 151 insertions(+), 144 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 8baa17e6f410..5f3323cc8321 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -48,7 +48,7 @@ pub mod transactions; use crate::eth::traits::RawTransactionForwarder; pub use receipt::ReceiptBuilder; -pub use traits::{BuildReceipt, EthBlocks, EthTransactions, LoadState, StateCacheDB}; +pub use traits::{BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, StateCacheDB}; pub use transactions::TransactionSource; /// `Eth` API trait. diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index e3688d8a0b46..6bee7996090f 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -20,7 +20,7 @@ use tracing::trace; use crate::{ eth::{ - api::{EthBlocks, EthTransactions, SpawnBlocking}, + api::{BuildReceipt, EthApiSpec, EthBlocks, EthState, EthTransactions}, error::EthApiError, revm_utils::EvmOverrides, EthApi, @@ -28,12 +28,10 @@ use crate::{ result::{internal_rpc_err, ToRpcResult}, }; -use super::{BuildReceipt, EthApiSpec}; - #[async_trait::async_trait] impl EthApiServer for EthApi where - Self: EthApiSpec + EthTransactions + BuildReceipt + SpawnBlocking, + Self: EthApiSpec + EthTransactions + BuildReceipt + EthState, Pool: TransactionPool + 'static, Provider: BlockReaderIdExt + ChainSpecProvider @@ -214,8 +212,7 @@ where /// Handler for: `eth_getBalance` async fn balance(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(SpawnBlocking::spawn_blocking_io(self, move |this| this.balance(address, block_number)) - .await?) + Ok(EthState::balance(self, address, block_number).await?) } /// Handler for: `eth_getStorageAt` @@ -226,10 +223,7 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - let res: B256 = SpawnBlocking::spawn_blocking_io(self, move |this| { - this.storage_at(address, index, block_number) - }) - .await?; + let res: B256 = EthState::storage_at(self, address, index, block_number).await?; Ok(res) } @@ -240,17 +234,13 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(SpawnBlocking::spawn_blocking_io(self, move |this| { - this.get_transaction_count(address, block_number) - }) - .await?) + Ok(EthState::transaction_count(self, address, block_number).await?) } /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_number: Option) -> Result { trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(SpawnBlocking::spawn_blocking_io(self, move |this| this.get_code(address, block_number)) - .await?) + Ok(EthState::get_code(self, address, block_number).await?) } /// Handler for: `eth_getHeaderByNumber` @@ -412,7 +402,7 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); - let res = Self::get_proof(self, address, keys, block_number).await; + let res = EthState::get_proof(self, address, keys, block_number).await; Ok(res.map_err(|e| match e { EthApiError::InvalidBlockRange => { diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index a5d79965f328..f0ad1bfcf256 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -1,92 +1,7 @@ //! Contains RPC handler implementations specific to state. -use crate::{ - eth::error::{EthApiError, EthResult}, - EthApi, -}; -use reth_evm::ConfigureEvm; -use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, U256}; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; -use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; -use reth_rpc_types_compat::proof::from_primitive_account_proof; -use reth_transaction_pool::TransactionPool; - -use super::LoadState; - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + Clone + 'static, - Network: Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - pub(crate) fn get_code(&self, address: Address, block_id: Option) -> EthResult { - Ok(self - .state_at_block_id_or_latest(block_id)? - .account_code(address)? - .unwrap_or_default() - .original_bytes()) - } - - pub(crate) fn balance(&self, address: Address, block_id: Option) -> EthResult { - Ok(self - .state_at_block_id_or_latest(block_id)? - .account_balance(address)? - .unwrap_or_default()) - } - - pub(crate) fn storage_at( - &self, - address: Address, - index: JsonStorageKey, - block_id: Option, - ) -> EthResult { - Ok(B256::new( - self.state_at_block_id_or_latest(block_id)? - .storage(address, index.0)? - .unwrap_or_default() - .to_be_bytes(), - )) - } - - pub(crate) async fn get_proof( - &self, - address: Address, - keys: Vec, - block_id: Option, - ) -> EthResult { - let chain_info = self.provider().chain_info()?; - let block_id = block_id.unwrap_or_default(); - - // if we are trying to create a proof for the latest block, but have a BlockId as input - // that is not BlockNumberOrTag::Latest, then we need to figure out whether or not the - // BlockId corresponds to the latest block - let is_latest_block = match block_id { - BlockId::Number(BlockNumberOrTag::Number(num)) => num == chain_info.best_number, - BlockId::Hash(hash) => hash == chain_info.best_hash.into(), - BlockId::Number(BlockNumberOrTag::Latest) => true, - _ => false, - }; - - // TODO: remove when HistoricalStateProviderRef::proof is implemented - if !is_latest_block { - return Err(EthApiError::InvalidBlockRange) - } - - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || { - let state = this.state_at_block_id(block_id)?; - let storage_keys = keys.iter().map(|key| key.0).collect::>(); - let proof = state.proof(address, &storage_keys)?; - Ok(from_primitive_account_proof(proof)) - }) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } -} +use crate::{eth::api::LoadState, EthApi}; +use reth_provider::StateProviderFactory; impl LoadState for EthApi where diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index b508f1b846b2..953ad228eb53 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -43,7 +43,7 @@ pub trait SpawnBlocking: Clone + Send + Sync + 'static { /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` /// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See /// . - fn spawn_tracing(&self, f: F) -> impl Future> + fn spawn_tracing(&self, f: F) -> impl Future> + Send where F: FnOnce(Self) -> EthResult + Send + 'static, R: Send + 'static, diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index 7ab1321d3d64..79f976922d07 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -9,5 +9,5 @@ pub mod transaction; pub use block::EthBlocks; pub use blocking_task::SpawnBlocking; pub use receipt::BuildReceipt; -pub use state::LoadState; +pub use state::{EthState, LoadState}; pub use transaction::{EthTransactions, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/traits/state.rs b/crates/rpc/rpc/src/eth/api/traits/state.rs index 3148ec2438ca..34af872cca30 100644 --- a/crates/rpc/rpc/src/eth/api/traits/state.rs +++ b/crates/rpc/rpc/src/eth/api/traits/state.rs @@ -1,9 +1,131 @@ //! Loads state from database. Helper trait for `eth_`transaction and state RPC methods. -use reth_primitives::{BlockId, B256}; +use futures::Future; +use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, U256}; use reth_provider::{StateProviderBox, StateProviderFactory}; +use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; +use reth_rpc_types_compat::proof::from_primitive_account_proof; +use reth_transaction_pool::{PoolTransaction, TransactionPool}; -use crate::eth::error::EthResult; +use crate::{ + eth::{ + api::SpawnBlocking, + error::{EthApiError, EthResult, RpcInvalidTransactionError}, + }, + EthApiSpec, +}; + +pub trait EthState: LoadState + SpawnBlocking { + /// Returns a handle for reading data from transaction pool. + /// + /// Data access in default trait method implementations. + fn pool(&self) -> &impl TransactionPool; + + /// Returns the number of transactions sent from an address at the given block identifier. + /// + /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will + /// look up the highest transaction in pool and return the next nonce (highest + 1). + fn transaction_count( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + if block_id == Some(BlockId::pending()) { + let address_txs = this.pool().get_transactions_by_sender(address); + if let Some(highest_nonce) = + address_txs.iter().map(|item| item.transaction.nonce()).max() + { + let tx_count = highest_nonce + .checked_add(1) + .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; + return Ok(U256::from(tx_count)) + } + } + + let state = this.state_at_block_id_or_latest(block_id)?; + Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) + }) + } + + fn get_code( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(this + .state_at_block_id_or_latest(block_id)? + .account_code(address)? + .unwrap_or_default() + .original_bytes()) + }) + } + + fn balance( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(this + .state_at_block_id_or_latest(block_id)? + .account_balance(address)? + .unwrap_or_default()) + }) + } + + fn storage_at( + &self, + address: Address, + index: JsonStorageKey, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(B256::new( + this.state_at_block_id_or_latest(block_id)? + .storage(address, index.0)? + .unwrap_or_default() + .to_be_bytes(), + )) + }) + } + + fn get_proof( + &self, + address: Address, + keys: Vec, + block_id: Option, + ) -> impl Future> + Send + where + Self: EthApiSpec, + { + let chain_info = self.chain_info()?; + let block_id = block_id.unwrap_or_default(); + + // if we are trying to create a proof for the latest block, but have a BlockId as input + // that is not BlockNumberOrTag::Latest, then we need to figure out whether or not the + // BlockId corresponds to the latest block + let is_latest_block = match block_id { + BlockId::Number(BlockNumberOrTag::Number(num)) => num == chain_info.best_number, + BlockId::Hash(hash) => hash == chain_info.best_hash.into(), + BlockId::Number(BlockNumberOrTag::Latest) => true, + _ => false, + }; + + // TODO: remove when HistoricalStateProviderRef::proof is implemented + if !is_latest_block { + return Err(EthApiError::InvalidBlockRange) + } + + self.spawn_tracing(move |this| { + let state = this.state_at_block_id(block_id); + let storage_keys = keys.iter().map(|key| key.0).collect::>(); + let proof = state.proof(address, &storage_keys)?; + Ok(from_primitive_account_proof(proof)) + }) + } +} /// Loads state from database. pub trait LoadState { diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 279a3b75f671..96215750976a 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -5,14 +5,14 @@ use std::sync::Arc; use reth_evm::ConfigureEvm; use reth_primitives::{ - revm::env::fill_block_env_with_coinbase, Address, BlockId, Bytes, - FromRecoveredPooledTransaction, Header, IntoRecoveredTransaction, Receipt, SealedBlock, - SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, B256, U256, + revm::env::fill_block_env_with_coinbase, BlockId, Bytes, FromRecoveredPooledTransaction, + Header, IntoRecoveredTransaction, Receipt, SealedBlock, SealedBlockWithSenders, + TransactionMeta, TransactionSigned, TxHash, B256, }; use reth_provider::{BlockReaderIdExt, ReceiptProvider, StateProviderBox, TransactionsProvider}; use reth_revm::database::StateProviderDatabase; use reth_rpc_types::{AnyTransactionReceipt, TransactionInfo, TransactionRequest}; -use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; +use reth_transaction_pool::{TransactionOrigin, TransactionPool}; use revm::{ db::CacheDB, primitives::{ @@ -29,9 +29,9 @@ use revm_primitives::{ use crate::{ eth::{ - api::{BuildReceipt, LoadState, SpawnBlocking}, + api::{BuildReceipt, EthState, LoadState, SpawnBlocking}, cache::EthStateCache, - error::{EthApiError, EthResult, RpcInvalidTransactionError}, + error::{EthApiError, EthResult}, revm_utils::{EvmOverrides, FillableTransaction}, traits::RawTransactionForwarder, utils::recover_raw_transaction, @@ -68,7 +68,8 @@ pub type StateCacheDB = CacheDB>; /// This implementation follows the behaviour of Geth and disables the basefee check for tracing. #[async_trait::async_trait] pub trait EthTransactions: Send + Sync { - /// Transaction pool with pending transactions. + /// Transaction pool with pending transactions. [`TransactionPool::Transaction`] is the + /// supported transaction type. type Pool: TransactionPool; /// Returns a handle for reading data from disk. @@ -461,31 +462,7 @@ pub trait EthTransactions: Send + Sync { /// Returns the hash of the signed transaction. async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult where - Self: EthApiSpec + LoadState; - - /// Returns the number of transactions sent from an address at the given block identifier. - /// - /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will - /// look up the highest transaction in pool and return the next nonce (highest + 1). - fn get_transaction_count(&self, address: Address, block_id: Option) -> EthResult - where - Self: LoadState, - { - if block_id == Some(BlockId::pending()) { - let address_txs = self.pool().get_transactions_by_sender(address); - if let Some(highest_nonce) = - address_txs.iter().map(|item| item.transaction.nonce()).max() - { - let tx_count = highest_nonce - .checked_add(1) - .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; - return Ok(U256::from(tx_count)) - } - } - - let state = self.state_at_block_id_or_latest(block_id)?; - Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) - } + Self: EthApiSpec + EthState; /// Prepares the state and env for the given [TransactionRequest] at the given [BlockId] and /// executes the closure on a new task returning the result of the closure. diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index a2931ee0572b..2eea6982075b 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -38,7 +38,7 @@ use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use crate::{ eth::{ api::{ - pending_block::PendingBlockEnv, BuildReceipt, EthTransactions, LoadState, + pending_block::PendingBlockEnv, BuildReceipt, EthState, EthTransactions, LoadState, SpawnBlocking, StateCacheDB, }, cache::EthStateCache, @@ -145,7 +145,10 @@ where self.block_by_id(block).await.map(|block| block.map(|block| block.body)) } - async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult { + async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult + where + Self: EthState, + { let from = match request.from { Some(from) => from, None => return Err(SignError::NoAccount.into()), @@ -153,7 +156,7 @@ where // set nonce if not already set before if request.nonce.is_none() { - let nonce = self.get_transaction_count(from, Some(BlockId::pending()))?; + let nonce = self.transaction_count(from, Some(BlockId::pending())).await?; // note: `.to()` can't panic because the nonce is constructed from a `u64` request.nonce = Some(nonce.to::()); } From ca19811a3774900d4806f6af032e4b82b61b78ac Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 5 Jun 2024 20:27:04 +0200 Subject: [PATCH 24/33] fixup! Move state rpc methods into new trait default impl --- crates/rpc/rpc/src/eth/api/server.rs | 2 +- crates/rpc/rpc/src/eth/api/state.rs | 25 ++++++++++++++++--- .../rpc/src/eth/api/traits/blocking_task.rs | 8 ++---- crates/rpc/rpc/src/eth/api/traits/state.rs | 13 +++++++--- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 6bee7996090f..21ff4c96c8a5 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -402,7 +402,7 @@ where block_number: Option, ) -> Result { trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); - let res = EthState::get_proof(self, address, keys, block_number).await; + let res = EthState::get_proof(self, address, keys, block_number)?.await; Ok(res.map_err(|e| match e { EthApiError::InvalidBlockRange => { diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index f0ad1bfcf256..ccf4fa232aaf 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -1,7 +1,22 @@ //! Contains RPC handler implementations specific to state. -use crate::{eth::api::LoadState, EthApi}; +use crate::{ + eth::api::{EthState, LoadState, SpawnBlocking}, + EthApi, +}; use reth_provider::StateProviderFactory; +use reth_transaction_pool::TransactionPool; + +impl EthState for EthApi +where + Self: SpawnBlocking + LoadState, + Pool: TransactionPool, +{ + #[inline] + fn pool(&self) -> &impl TransactionPool { + self.inner.pool() + } +} impl LoadState for EthApi where @@ -19,7 +34,9 @@ mod tests { cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, FeeHistoryCacheConfig, }; use reth_evm_ethereum::EthEvmConfig; - use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, StorageKey, StorageValue}; + use reth_primitives::{ + constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, U256, + }; use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider}; use reth_tasks::pool::BlockingTaskPool; use reth_transaction_pool::test_utils::testing_pool; @@ -45,7 +62,7 @@ mod tests { None, ); let address = Address::random(); - let storage = eth_api.storage_at(address, U256::ZERO.into(), None).unwrap(); + let storage = eth_api.storage_at(address, U256::ZERO.into(), None).await.unwrap(); assert_eq!(storage, U256::ZERO.to_be_bytes()); // === Mock === @@ -71,7 +88,7 @@ mod tests { ); let storage_key: U256 = storage_key.into(); - let storage = eth_api.storage_at(address, storage_key.into(), None).unwrap(); + let storage = eth_api.storage_at(address, storage_key.into(), None).await.unwrap(); assert_eq!(storage, storage_value.to_be_bytes()); } } diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 953ad228eb53..0e584de0dc36 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -49,11 +49,7 @@ pub trait SpawnBlocking: Clone + Send + Sync + 'static { R: Send + 'static, { let this = self.clone(); - async move { - self.tracing_task_pool() - .spawn(move || f(this)) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } + let fut = self.tracing_task_pool().spawn(move || f(this)); + async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? } } } diff --git a/crates/rpc/rpc/src/eth/api/traits/state.rs b/crates/rpc/rpc/src/eth/api/traits/state.rs index 34af872cca30..98359ef3fc71 100644 --- a/crates/rpc/rpc/src/eth/api/traits/state.rs +++ b/crates/rpc/rpc/src/eth/api/traits/state.rs @@ -15,6 +15,7 @@ use crate::{ EthApiSpec, }; +/// Helper methods for `eth_` methods relating to state (accounts). pub trait EthState: LoadState + SpawnBlocking { /// Returns a handle for reading data from transaction pool. /// @@ -48,6 +49,7 @@ pub trait EthState: LoadState + SpawnBlocking { }) } + /// Returns code of given account, at given blocknumber. fn get_code( &self, address: Address, @@ -62,6 +64,7 @@ pub trait EthState: LoadState + SpawnBlocking { }) } + /// Returns balance of given account, at given blocknumber. fn balance( &self, address: Address, @@ -75,6 +78,7 @@ pub trait EthState: LoadState + SpawnBlocking { }) } + /// Returns values stored of given account, at given blocknumber. fn storage_at( &self, address: Address, @@ -91,12 +95,13 @@ pub trait EthState: LoadState + SpawnBlocking { }) } + /// Returns values stored of given account, with Merkle-proof, at given blocknumber. fn get_proof( &self, address: Address, keys: Vec, block_id: Option, - ) -> impl Future> + Send + ) -> EthResult> + Send> where Self: EthApiSpec, { @@ -118,12 +123,12 @@ pub trait EthState: LoadState + SpawnBlocking { return Err(EthApiError::InvalidBlockRange) } - self.spawn_tracing(move |this| { - let state = this.state_at_block_id(block_id); + Ok(self.spawn_tracing(move |this| { + let state = this.state_at_block_id(block_id)?; let storage_keys = keys.iter().map(|key| key.0).collect::>(); let proof = state.proof(address, &storage_keys)?; Ok(from_primitive_account_proof(proof)) - }) + })) } } From 8ee373c460ea357710141774d0a076b62e798d47 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 6 Jun 2024 13:19:52 +0200 Subject: [PATCH 25/33] Move EthTransactions impl to default trait methods --- crates/rpc/rpc/src/debug.rs | 4 +- crates/rpc/rpc/src/eth/api/mod.rs | 5 +- .../rpc/rpc/src/eth/api/traits/transaction.rs | 53 +++++++++++-- crates/rpc/rpc/src/eth/api/transactions.rs | 76 +------------------ crates/rpc/rpc/src/eth/bundle.rs | 4 +- crates/rpc/rpc/src/trace.rs | 6 +- 6 files changed, 58 insertions(+), 90 deletions(-) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index b5fc8b7c49d6..026fea2d810a 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,6 +1,6 @@ use crate::{ eth::{ - api::{traits::SpawnBlocking, EthTransactions, LoadState}, + api::{EthTransactions, LoadState, SpawnBlocking}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, }, @@ -65,7 +65,7 @@ impl DebugApi { impl DebugApi where Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + LoadState + 'static, + Eth: EthTransactions + LoadState + SpawnBlocking + 'static, { /// Acquires a permit to execute a tracing call. async fn acquire_trace_permit(&self) -> Result { diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 5f3323cc8321..37d865bccff1 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -20,7 +20,6 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::Mutex; -use traits::SpawnBlocking; use crate::eth::{ api::{ @@ -48,7 +47,9 @@ pub mod transactions; use crate::eth::traits::RawTransactionForwarder; pub use receipt::ReceiptBuilder; -pub use traits::{BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, StateCacheDB}; +pub use traits::{ + BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, SpawnBlocking, StateCacheDB, +}; pub use transactions::TransactionSource; /// `Eth` API trait. diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 96215750976a..337d5da140a4 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -205,9 +205,16 @@ pub trait EthTransactions: Send + Sync { /// Executes the closure with the state that corresponds to the given [BlockId] on a new task async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult where - Self: LoadState, + Self: LoadState + SpawnBlocking, F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, - T: Send + 'static; + T: Send + 'static, + { + self.spawn_tracing(move |this| { + let state = this.state_at_block_id(at)?; + f(state) + }) + .await + } /// Returns the revm evm env for the requested [BlockId] /// @@ -520,7 +527,15 @@ pub trait EthTransactions: Send + Sync { ) -> EthResult where Self: LoadState, - F: FnOnce(TracingInspector, ResultAndState) -> EthResult; + F: FnOnce(TracingInspector, ResultAndState) -> EthResult, + { + self.with_state_at_block(at, |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut inspector = TracingInspector::new(config); + let (res, _) = self.inspect(&mut db, env, &mut inspector)?; + f(inspector, res) + }) + } /// Same as [Self::trace_at] but also provides the used database to the callback. /// @@ -537,15 +552,41 @@ pub trait EthTransactions: Send + Sync { f: F, ) -> EthResult where - Self: LoadState, + Self: LoadState + SpawnBlocking, F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static; + R: Send + 'static, + { + let this = self.clone(); + self.spawn_with_state_at_block(at, move |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut inspector = TracingInspector::new(config); + let (res, _) = this.inspect(&mut db, env, &mut inspector)?; + f(inspector, res, db) + }) + .await + } /// Fetches the transaction and the transaction's block async fn transaction_and_block( &self, hash: B256, - ) -> EthResult>; + ) -> EthResult> + where + Self: SpawnBlocking, + { + let (transaction, at) = match self.transaction_by_hash_at(hash).await? { + None => return Ok(None), + Some(res) => res, + }; + + // Note: this is always either hash or pending + let block_hash = match at { + BlockId::Hash(hash) => hash.block_hash, + _ => return Ok(None), + }; + let block = self.cache().get_block_with_senders(block_hash).await?; + Ok(block.map(|block| (transaction, block.seal(block_hash)))) + } /// Retrieves the transaction if it exists and returns its trace. /// diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 2eea6982075b..ca3ca029cea5 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -13,7 +13,7 @@ use reth_primitives::{ }; use reth_provider::{ BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ReceiptProvider, - StateProviderBox, StateProviderFactory, TransactionsProvider, + StateProviderFactory, TransactionsProvider, }; use reth_revm::database::StateProviderDatabase; use reth_rpc_types::{ @@ -33,7 +33,6 @@ use revm::{ }, Inspector, }; -use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use crate::{ eth::{ @@ -96,19 +95,6 @@ where self.inner.gas_cap } - async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - Self: LoadState, - F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, - T: Send + 'static, - { - self.spawn_tracing(move |this| { - let state = this.state_at_block_id(at)?; - f(state) - }) - .await - } - async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> where Self: LoadState, @@ -408,66 +394,6 @@ where .await } - fn trace_at( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - Self: LoadState, - F: FnOnce(TracingInspector, ResultAndState) -> EthResult, - { - let this = self.clone(); - self.with_state_at_block(at, |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let mut inspector = TracingInspector::new(config); - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - f(inspector, res) - }) - } - - async fn spawn_trace_at_with_state( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - Self: LoadState, - F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static, - { - let this = self.clone(); - self.spawn_with_state_at_block(at, move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let mut inspector = TracingInspector::new(config); - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - f(inspector, res, db) - }) - .await - } - - async fn transaction_and_block( - &self, - hash: B256, - ) -> EthResult> { - let (transaction, at) = match self.transaction_by_hash_at(hash).await? { - None => return Ok(None), - Some(res) => res, - }; - - // Note: this is always either hash or pending - let block_hash = match at { - BlockId::Hash(hash) => hash.block_hash, - _ => return Ok(None), - }; - let block = self.cache().get_block_with_senders(block_hash).await?; - Ok(block.map(|block| (transaction, block.seal(block_hash)))) - } - async fn spawn_replay_transaction(&self, hash: B256, f: F) -> EthResult> where Self: LoadState, diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 2915a6c9779f..494ba12629a3 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -1,7 +1,7 @@ //! `Eth` bundle implementation and helpers. use crate::eth::{ - api::EthTransactions, + api::{EthTransactions, SpawnBlocking}, error::{EthApiError, EthResult, RpcInvalidTransactionError}, revm_utils::FillableTransaction, utils::recover_raw_transaction, @@ -41,7 +41,7 @@ impl EthBundle { impl EthBundle where - Eth: EthTransactions + LoadState + 'static, + Eth: EthTransactions + LoadState + SpawnBlocking + '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 diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 3b1cb4019b86..6a9c925621e4 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,5 +1,5 @@ use crate::eth::{ - api::{EthTransactions, LoadState}, + api::{EthTransactions, LoadState, SpawnBlocking}, error::{EthApiError, EthResult}, revm_utils::{prepare_call_env, EvmOverrides}, utils::recover_raw_transaction, @@ -72,7 +72,7 @@ impl TraceApi { impl TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + LoadState + 'static, + Eth: EthTransactions + LoadState + SpawnBlocking + 'static, { /// Executes the given call and returns a number of possible traces for it. pub async fn trace_call(&self, trace_request: TraceCallRequest) -> EthResult { @@ -485,7 +485,7 @@ where impl TraceApiServer for TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + LoadState + 'static, + Eth: EthTransactions + LoadState + SpawnBlocking + 'static, { /// Executes the given call and returns a number of possible traces for it. /// From 6dfac1a6c21c1c4782e3c2fd4bdc54a8d46d8710 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 6 Jun 2024 14:25:57 +0200 Subject: [PATCH 26/33] Add trait for pending block --- crates/rpc/rpc/Cargo.toml | 2 +- crates/rpc/rpc/src/eth/api/block.rs | 22 ++- crates/rpc/rpc/src/eth/api/call.rs | 9 +- crates/rpc/rpc/src/eth/api/fees.rs | 3 + crates/rpc/rpc/src/eth/api/mod.rs | 145 ++---------------- crates/rpc/rpc/src/eth/api/pending_block.rs | 81 +++++++--- crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 + .../rpc/src/eth/api/traits/pending_block.rs | 144 +++++++++++++++++ crates/rpc/rpc/src/eth/api/transactions.rs | 6 +- 9 files changed, 256 insertions(+), 158 deletions(-) create mode 100644 crates/rpc/rpc/src/eth/api/traits/pending_block.rs diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index c005020c7ce0..26bacfdc9f62 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -75,7 +75,7 @@ tracing.workspace = true tracing-futures = "0.2" schnellru.workspace = true futures.workspace = true -derive_more.workspace = true +derive_more = { workspace = true, default-features = false, features = ["deref", "deref_mut", "constructor"] } dyn-clone.workspace = true [dev-dependencies] diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs index 485c8de48a39..deb24be85470 100644 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ b/crates/rpc/rpc/src/eth/api/block.rs @@ -18,6 +18,8 @@ use reth_transaction_pool::TransactionPool; use crate::eth::api::EthBlocks; +use super::traits::LoadPendingBlock; + impl EthBlocks for EthApi where Provider: BlockReaderIdExt + BlockReader + ReceiptProvider, @@ -94,7 +96,10 @@ where pub(crate) async fn block( &self, block_id: impl Into, - ) -> EthResult> { + ) -> EthResult> + where + Self: LoadPendingBlock, + { self.block_with_senders(block_id) .await .map(|maybe_block| maybe_block.map(|block| block.block)) @@ -104,7 +109,10 @@ where pub(crate) async fn block_with_senders( &self, block_id: impl Into, - ) -> EthResult> { + ) -> EthResult> + where + Self: LoadPendingBlock, + { let block_id = block_id.into(); if block_id.is_pending() { @@ -133,7 +141,10 @@ where &self, block_id: impl Into, full: bool, - ) -> EthResult> { + ) -> EthResult> + where + Self: LoadPendingBlock, + { let block = match self.block_with_senders(block_id).await? { Some(block) => block, None => return Ok(None), @@ -151,7 +162,10 @@ where pub(crate) async fn rpc_block_header( &self, block_id: impl Into, - ) -> EthResult> { + ) -> 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 4d20487f233e..a5a79be97902 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -2,7 +2,7 @@ use crate::{ eth::{ - api::{EthTransactions, SpawnBlocking}, + api::{EthTransactions, LoadPendingBlock, LoadState, SpawnBlocking}, error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError}, revm_utils::{ apply_state_overrides, build_call_evm_env, caller_gas_allowance, @@ -34,8 +34,6 @@ use revm::{ use revm_inspectors::access_list::AccessListInspector; use tracing::trace; -use super::LoadState; - // Gas per transaction not creating a contract. const MIN_TRANSACTION_GAS: u64 = 21_000u64; /// Allowed error ratio for gas estimation @@ -88,7 +86,10 @@ where bundle: Bundle, state_context: Option, mut state_override: Option, - ) -> EthResult> { + ) -> EthResult> + where + Self: LoadPendingBlock, + { let Bundle { transactions, block_override } = bundle; if transactions.is_empty() { return Err(EthApiError::InvalidParams(String::from("transactions are empty."))) diff --git a/crates/rpc/rpc/src/eth/api/fees.rs b/crates/rpc/rpc/src/eth/api/fees.rs index 68789674ce5d..97bdd7a014bd 100644 --- a/crates/rpc/rpc/src/eth/api/fees.rs +++ b/crates/rpc/rpc/src/eth/api/fees.rs @@ -15,8 +15,11 @@ use reth_rpc_types::FeeHistory; use reth_transaction_pool::TransactionPool; use tracing::debug; +use super::traits::LoadPendingBlock; + impl EthApi where + Self: LoadPendingBlock, Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 37d865bccff1..44fe2bfc1ade 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -1,43 +1,29 @@ //! The entire implementation of the namespace is quite large, hence it is divided across several //! files. +use std::{fmt::Debug, sync::Arc}; + use async_trait::async_trait; use reth_errors::{RethError, RethResult}; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; -use reth_primitives::{ - revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Address, BlockNumberOrTag, ChainInfo, SealedBlockWithSenders, SealedHeader, U256, U64, -}; +use reth_primitives::{Address, BlockNumberOrTag, ChainInfo, U256, U64}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::{SyncInfo, SyncStatus}; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::TransactionPool; -use revm_primitives::{CfgEnv, SpecId}; -use std::{ - fmt::Debug, - sync::Arc, - time::{Duration, Instant}, -}; use tokio::sync::Mutex; use crate::eth::{ - api::{ - fee_history::FeeHistoryCache, - pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}, - }, - cache::EthStateCache, - error::{EthApiError, EthResult}, - gas_oracle::GasPriceOracle, + api::fee_history::FeeHistoryCache, cache::EthStateCache, gas_oracle::GasPriceOracle, signer::EthSigner, }; pub mod block; mod call; pub(crate) mod fee_history; - mod fees; -mod pending_block; +pub mod pending_block; pub mod receipt; mod server; mod sign; @@ -46,9 +32,11 @@ pub mod traits; pub mod transactions; use crate::eth::traits::RawTransactionForwarder; +pub use pending_block::PendingBlock; pub use receipt::ReceiptBuilder; pub use traits::{ - BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, SpawnBlocking, StateCacheDB, + BuildReceipt, EthBlocks, EthState, EthTransactions, LoadPendingBlock, LoadState, SpawnBlocking, + StateCacheDB, }; pub use transactions::TransactionSource; @@ -201,120 +189,15 @@ where } } -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + 'static, - Network: NetworkInfo + 'static, - EvmConfig: ConfigureEvm, -{ - /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block - /// - /// If no pending block is available, this will derive it from the `latest` block - pub(crate) fn pending_block_env_and_cfg(&self) -> EthResult { - let origin: PendingBlockEnvOrigin = if let Some(pending) = - self.provider().pending_block_with_senders()? - { - PendingBlockEnvOrigin::ActualPending(pending) - } else { - // no pending block from the CL yet, so we use the latest block and modify the env - // values that we can - let latest = - self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?; - - let (mut latest_header, block_hash) = latest.split(); - // child block - latest_header.number += 1; - // assumed child block is in the next slot: 12s - latest_header.timestamp += 12; - // base fee of the child block - let chain_spec = self.provider().chain_spec(); - - latest_header.base_fee_per_gas = latest_header.next_block_base_fee( - chain_spec.base_fee_params_at_timestamp(latest_header.timestamp), - ); - - // update excess blob gas consumed above target - latest_header.excess_blob_gas = latest_header.next_block_excess_blob_gas(); - - // we're reusing the same block hash because we need this to lookup the block's state - let latest = SealedHeader::new(latest_header, block_hash); - - PendingBlockEnvOrigin::DerivedFromLatest(latest) - }; - - let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); - - let mut block_env = BlockEnv::default(); - // Note: for the PENDING block we assume it is past the known merge block and thus this will - // not fail when looking up the total difficulty value for the blockenv. - self.provider().fill_env_with_header( - &mut cfg, - &mut block_env, - origin.header(), - self.inner.evm_config.clone(), - )?; - - Ok(PendingBlockEnv { cfg, block_env, origin }) - } - - /// Returns the locally built pending block - pub(crate) async fn local_pending_block(&self) -> EthResult> { - let pending = self.pending_block_env_and_cfg()?; - if pending.origin.is_actual_pending() { - return Ok(pending.origin.into_actual_pending()) - } - - let mut lock = self.inner.pending_block.lock().await; - - let now = Instant::now(); - - // check if the block is still good - if let Some(pending_block) = lock.as_ref() { - // this is guaranteed to be the `latest` header - if pending.block_env.number.to::() == pending_block.block.number && - pending.origin.header().hash() == pending_block.block.parent_hash && - now <= pending_block.expires_at - { - return Ok(Some(pending_block.block.clone())) - } - } - - // no pending block from the CL yet, so we need to build it ourselves via txpool - let pending_block = match self - .spawn_blocking_io(move |this| { - // we rebuild the block - pending.build_block(this.provider(), this.pool()) - }) - .await - { - Ok(block) => block, - Err(err) => { - tracing::debug!(target: "rpc", "Failed to build pending block: {:?}", err); - return Ok(None) - } - }; - - let now = Instant::now(); - *lock = Some(PendingBlock { - block: pending_block.clone(), - expires_at: now + Duration::from_secs(1), - }); - - Ok(Some(pending_block)) - } -} - -impl std::fmt::Debug - for EthApi +impl std::fmt::Debug + for EthApi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthApi").finish_non_exhaustive() } } -impl Clone for EthApi { +impl Clone for EthApi { fn clone(&self) -> Self { Self { inner: Arc::clone(&self.inner) } } @@ -464,6 +347,12 @@ impl EthApiInner &Mutex> { + &self.pending_block + } + /// Returns a handle to the task spawner. #[inline] pub const fn task_spawner(&self) -> &dyn TaskSpawner { diff --git a/crates/rpc/rpc/src/eth/api/pending_block.rs b/crates/rpc/rpc/src/eth/api/pending_block.rs index 276796b137ea..eeec611a0d2c 100644 --- a/crates/rpc/rpc/src/eth/api/pending_block.rs +++ b/crates/rpc/rpc/src/eth/api/pending_block.rs @@ -1,7 +1,10 @@ //! Support for building a pending block via local txpool. -use crate::eth::error::{EthApiError, EthResult}; +use std::time::Instant; + +use derive_more::Constructor; use reth_errors::ProviderError; +use reth_evm::ConfigureEvm; use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, proofs, @@ -13,7 +16,10 @@ use reth_primitives::{ Block, BlockId, BlockNumberOrTag, ChainSpec, Header, IntoRecoveredTransaction, Receipt, Receipts, Requests, SealedBlockWithSenders, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256, }; -use reth_provider::{BundleStateWithReceipts, ChainSpecProvider, StateProviderFactory}; +use reth_provider::{ + BlockReaderIdExt, BundleStateWithReceipts, ChainSpecProvider, EvmEnvProvider, + StateProviderFactory, +}; use reth_revm::{ database::StateProviderDatabase, state_change::{ @@ -24,17 +30,56 @@ use reth_revm::{ use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; use revm::{db::states::bundle_state::BundleRetention, Database, DatabaseCommit, State}; use revm_primitives::EnvWithHandlerCfg; -use std::time::Instant; +use tokio::sync::Mutex; + +use crate::{ + eth::{ + api::{LoadPendingBlock, SpawnBlocking}, + error::{EthApiError, EthResult}, + }, + EthApi, +}; + +impl LoadPendingBlock + for EthApi +where + Self: SpawnBlocking, + 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() + } +} /// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block -#[derive(Debug, Clone)] -pub(crate) struct PendingBlockEnv { +#[derive(Debug, Clone, Constructor)] +pub struct PendingBlockEnv { /// Configured [`CfgEnvWithHandlerCfg`] for the pending block. - pub(crate) cfg: CfgEnvWithHandlerCfg, + pub cfg: CfgEnvWithHandlerCfg, /// Configured [`BlockEnv`] for the pending block. - pub(crate) block_env: BlockEnv, + pub block_env: BlockEnv, /// Origin block for the config - pub(crate) origin: PendingBlockEnvOrigin, + pub origin: PendingBlockEnvOrigin, } impl PendingBlockEnv { @@ -44,7 +89,7 @@ impl PendingBlockEnv { /// /// After Cancun, if the origin is the actual pending block, the block includes the EIP-4788 pre /// block contract call using the parent beacon block root received from the CL. - pub(crate) fn build_block( + pub fn build_block( self, client: &Client, pool: &Pool, @@ -358,7 +403,7 @@ where /// The origin for a configured [`PendingBlockEnv`] #[derive(Clone, Debug)] -pub(crate) enum PendingBlockEnvOrigin { +pub enum PendingBlockEnvOrigin { /// The pending block as received from the CL. ActualPending(SealedBlockWithSenders), /// The _modified_ header of the latest block. @@ -372,12 +417,12 @@ pub(crate) enum PendingBlockEnvOrigin { impl PendingBlockEnvOrigin { /// Returns true if the origin is the actual pending block as received from the CL. - pub(crate) const fn is_actual_pending(&self) -> bool { + pub const fn is_actual_pending(&self) -> bool { matches!(self, Self::ActualPending(_)) } /// Consumes the type and returns the actual pending block. - pub(crate) fn into_actual_pending(self) -> Option { + pub fn into_actual_pending(self) -> Option { match self { Self::ActualPending(block) => Some(block), _ => None, @@ -388,7 +433,7 @@ impl PendingBlockEnvOrigin { /// /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely /// identify the block by its hash (latest block). - pub(crate) fn state_block_id(&self) -> BlockId { + pub fn state_block_id(&self) -> BlockId { match self { Self::ActualPending(_) => BlockNumberOrTag::Pending.into(), Self::DerivedFromLatest(header) => BlockId::Hash(header.hash().into()), @@ -408,7 +453,7 @@ impl PendingBlockEnvOrigin { } /// Returns the header this pending block is based on. - pub(crate) fn header(&self) -> &SealedHeader { + pub fn header(&self) -> &SealedHeader { match self { Self::ActualPending(block) => &block.header, Self::DerivedFromLatest(header) => header, @@ -417,10 +462,10 @@ impl PendingBlockEnvOrigin { } /// In memory pending block for `pending` tag -#[derive(Debug)] -pub(crate) struct PendingBlock { +#[derive(Debug, Constructor)] +pub struct PendingBlock { /// The cached pending block - pub(crate) block: SealedBlockWithSenders, + pub block: SealedBlockWithSenders, /// Timestamp when the pending block is considered outdated - pub(crate) expires_at: Instant, + pub expires_at: Instant, } diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index 79f976922d07..37f49cccc9e3 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -2,12 +2,14 @@ pub mod block; pub mod blocking_task; +pub mod pending_block; pub mod receipt; pub mod state; pub mod transaction; pub use block::EthBlocks; pub use blocking_task::SpawnBlocking; +pub use pending_block::LoadPendingBlock; pub use receipt::BuildReceipt; pub use state::{EthState, LoadState}; pub use transaction::{EthTransactions, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/traits/pending_block.rs b/crates/rpc/rpc/src/eth/api/traits/pending_block.rs new file mode 100644 index 000000000000..6790731c8edc --- /dev/null +++ b/crates/rpc/rpc/src/eth/api/traits/pending_block.rs @@ -0,0 +1,144 @@ +//! Loads a pending block from database. Helper trait for `eth_` block and transaction RPC methods. + +use std::time::{Duration, Instant}; + +use futures::Future; +use reth_evm::ConfigureEvm; +use reth_primitives::{SealedBlockWithSenders, SealedHeader}; +use reth_provider::{ + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, +}; +use reth_transaction_pool::TransactionPool; +use revm_primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}; +use tokio::sync::Mutex; +use tracing::debug; + +use crate::eth::{ + api::{ + pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}, + SpawnBlocking, + }, + error::{EthApiError, EthResult}, +}; + +/// Loads a pending block from database. +pub trait LoadPendingBlock: SpawnBlocking { + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider( + &self, + ) -> &(impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory); + + /// Returns a handle for reading data from transaction pool. + /// + /// Data access in default (L1) trait method implementations. + fn pool(&self) -> &impl TransactionPool; + + /// Returns a handle to the pending block. + /// + /// Data access in default (L1) trait method implementations. + fn pending_block(&self) -> &Mutex>; + + /// Returns a handle for reading evm config. + /// + /// Data access in default (L1) trait method implementations. + fn evm_config(&self) -> &impl ConfigureEvm; + + /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block + /// + /// If no pending block is available, this will derive it from the `latest` block + fn pending_block_env_and_cfg(&self) -> EthResult { + let origin: PendingBlockEnvOrigin = if let Some(pending) = + self.provider().pending_block_with_senders()? + { + PendingBlockEnvOrigin::ActualPending(pending) + } else { + // no pending block from the CL yet, so we use the latest block and modify the env + // values that we can + let latest = + self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?; + + let (mut latest_header, block_hash) = latest.split(); + // child block + latest_header.number += 1; + // assumed child block is in the next slot: 12s + latest_header.timestamp += 12; + // base fee of the child block + let chain_spec = self.provider().chain_spec(); + + latest_header.base_fee_per_gas = latest_header.next_block_base_fee( + chain_spec.base_fee_params_at_timestamp(latest_header.timestamp), + ); + + // update excess blob gas consumed above target + latest_header.excess_blob_gas = latest_header.next_block_excess_blob_gas(); + + // we're reusing the same block hash because we need this to lookup the block's state + let latest = SealedHeader::new(latest_header, block_hash); + + PendingBlockEnvOrigin::DerivedFromLatest(latest) + }; + + let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); + + let mut block_env = BlockEnv::default(); + // Note: for the PENDING block we assume it is past the known merge block and thus this will + // not fail when looking up the total difficulty value for the blockenv. + self.provider().fill_env_with_header( + &mut cfg, + &mut block_env, + origin.header(), + self.evm_config().clone(), + )?; + + Ok(PendingBlockEnv::new(cfg, block_env, origin)) + } + + /// Returns the locally built pending block + fn local_pending_block( + &self, + ) -> impl Future>> { + async move { + let pending = self.pending_block_env_and_cfg()?; + if pending.origin.is_actual_pending() { + return Ok(pending.origin.into_actual_pending()) + } + + let mut lock = self.pending_block().lock().await; + + let now = Instant::now(); + + // check if the block is still good + if let Some(pending_block) = lock.as_ref() { + // this is guaranteed to be the `latest` header + if pending.block_env.number.to::() == pending_block.block.number && + pending.origin.header().hash() == pending_block.block.parent_hash && + now <= pending_block.expires_at + { + return Ok(Some(pending_block.block.clone())) + } + } + + // no pending block from the CL yet, so we need to build it ourselves via txpool + let pending_block = match self + .spawn_blocking_io(move |this| { + // we rebuild the block + pending.build_block(this.provider(), this.pool()) + }) + .await + { + Ok(block) => block, + Err(err) => { + debug!(target: "rpc", "Failed to build pending block: {:?}", err); + return Ok(None) + } + }; + + let now = Instant::now(); + *lock = Some(PendingBlock::new(pending_block.clone(), now + Duration::from_secs(1))); + + Ok(Some(pending_block)) + } + } +} diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index ca3ca029cea5..72854418efb4 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -37,8 +37,8 @@ use revm::{ use crate::{ eth::{ api::{ - pending_block::PendingBlockEnv, BuildReceipt, EthState, EthTransactions, LoadState, - SpawnBlocking, StateCacheDB, + pending_block::PendingBlockEnv, BuildReceipt, EthState, EthTransactions, + LoadPendingBlock, LoadState, SpawnBlocking, StateCacheDB, }, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, @@ -97,7 +97,7 @@ where async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> where - Self: LoadState, + Self: LoadState + LoadPendingBlock, { if at.is_pending() { let PendingBlockEnv { cfg, block_env, origin } = self.pending_block_env_and_cfg()?; From 3c0b7ab951ea8c29ceb1b35e1f2de7d93eea2739 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 6 Jun 2024 15:13:28 +0200 Subject: [PATCH 27/33] Fix lint --- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index da1a0d23ff64..337d5da140a4 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -40,8 +40,6 @@ use crate::{ EthApiSpec, }; -use super::SpawnBlocking; - /// Helper alias type for the state's [`CacheDB`] pub type StateCacheDB = CacheDB>; From e93cb32baacd3bdf0199a52902ef8bcaa2b016d9 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 15:44:56 +0200 Subject: [PATCH 28/33] Nitpick Co-authored-by: Matthias Seitz --- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 337d5da140a4..f10b30edb00a 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -2,7 +2,6 @@ //! network. use std::sync::Arc; - use reth_evm::ConfigureEvm; use reth_primitives::{ revm::env::fill_block_env_with_coinbase, BlockId, Bytes, FromRecoveredPooledTransaction, From b1a31607de1df1d707f3e4bf405cbcd32e4c591d Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 15:38:04 +0200 Subject: [PATCH 29/33] Return impl types without ref --- Cargo.lock | 1 + crates/evm/src/lib.rs | 2 ++ crates/optimism/node/src/rpc.rs | 2 +- crates/optimism/rpc/src/block.rs | 2 +- crates/optimism/rpc/src/lib.rs | 1 + crates/rpc/rpc/src/eth/api/block.rs | 2 +- crates/rpc/rpc/src/eth/api/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/state.rs | 4 ++-- crates/rpc/rpc/src/eth/api/traits/block.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/blocking_task.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/state.rs | 5 +++-- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 2 +- crates/rpc/rpc/src/eth/api/transactions.rs | 2 +- crates/storage/storage-api/src/receipts.rs | 1 + crates/tasks/Cargo.toml | 1 + crates/tasks/src/lib.rs | 2 ++ crates/transaction-pool/src/traits.rs | 4 ++-- 17 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0590d86b9cd7..fd8c646cff98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7900,6 +7900,7 @@ dependencies = [ name = "reth-tasks" version = "0.2.0-beta.8" dependencies = [ + "auto_impl", "dyn-clone", "futures-util", "metrics", diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index f74dc97c552f..6cd43e0c277c 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -24,6 +24,7 @@ pub mod provider; pub mod test_utils; /// Trait for configuring the EVM for executing full blocks. +#[auto_impl::auto_impl(&, Arc)] pub trait ConfigureEvm: ConfigureEvmEnv { /// Associated type for the default external context that should be configured for the EVM. type DefaultExternalContext<'a>; @@ -95,6 +96,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// This represents the set of methods used to configure the EVM's environment before block /// execution. +#[auto_impl::auto_impl(&, Arc)] pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { /// Fill transaction environment from a [`TransactionSigned`] and the given sender address. fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address); diff --git a/crates/optimism/node/src/rpc.rs b/crates/optimism/node/src/rpc.rs index be5f81af7e8d..433a38f325bc 100644 --- a/crates/optimism/node/src/rpc.rs +++ b/crates/optimism/node/src/rpc.rs @@ -3,8 +3,8 @@ use jsonrpsee::types::ErrorObject; use reqwest::Client; use reth_rpc::eth::{ + api::RawTransactionForwarder, error::{EthApiError, EthResult}, - traits::RawTransactionForwarder, }; use reth_rpc_types::ToRpcError; use std::sync::{atomic::AtomicUsize, Arc}; diff --git a/crates/optimism/rpc/src/block.rs b/crates/optimism/rpc/src/block.rs index 78681f8cdb3d..fa3e5b805c23 100644 --- a/crates/optimism/rpc/src/block.rs +++ b/crates/optimism/rpc/src/block.rs @@ -18,7 +18,7 @@ where Provider: BlockReaderIdExt + ChainSpecProvider, { #[inline] - fn provider(&self) -> &impl BlockReaderIdExt { + fn provider(&self) -> impl BlockReaderIdExt { self.inner.provider() } diff --git a/crates/optimism/rpc/src/lib.rs b/crates/optimism/rpc/src/lib.rs index a6604dc9e888..aacb99decf90 100644 --- a/crates/optimism/rpc/src/lib.rs +++ b/crates/optimism/rpc/src/lib.rs @@ -21,6 +21,7 @@ pub mod transaction; /// This type provides OP specific extension of default functionality for handling `eth_` related /// requests. See [`EthApi`](reth_rpc::EthApi) for the default L1 implementation. #[allow(missing_debug_implementations)] +#[allow(dead_code)] pub struct OptimismApi { /// All nested fields bundled together. inner: Arc>, diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs index 485c8de48a39..e7aea4e370a8 100644 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ b/crates/rpc/rpc/src/eth/api/block.rs @@ -23,7 +23,7 @@ where Provider: BlockReaderIdExt + BlockReader + ReceiptProvider, { #[inline] - fn provider(&self) -> &impl BlockReaderIdExt { + fn provider(&self) -> impl BlockReaderIdExt { self.inner.provider() } } diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 37d865bccff1..53ecdb52b3a7 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -380,7 +380,7 @@ impl SpawnBlocking where Self: Send + Sync + 'static, { - fn io_task_spawner(&self) -> &dyn TaskSpawner { + fn io_task_spawner(&self) -> impl TaskSpawner { self.inner.task_spawner() } diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index ccf4fa232aaf..a315370fd3f8 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -13,7 +13,7 @@ where Pool: TransactionPool, { #[inline] - fn pool(&self) -> &impl TransactionPool { + fn pool(&self) -> impl TransactionPool { self.inner.pool() } } @@ -22,7 +22,7 @@ impl LoadState for EthApi &impl StateProviderFactory { + fn provider(&self) -> impl StateProviderFactory { &self.inner.provider } } diff --git a/crates/rpc/rpc/src/eth/api/traits/block.rs b/crates/rpc/rpc/src/eth/api/traits/block.rs index 510afe741950..34f3bfefa9d7 100644 --- a/crates/rpc/rpc/src/eth/api/traits/block.rs +++ b/crates/rpc/rpc/src/eth/api/traits/block.rs @@ -18,7 +18,7 @@ pub trait EthBlocks { /// Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. - fn provider(&self) -> &impl BlockReaderIdExt; + fn provider(&self) -> impl BlockReaderIdExt; /// Helper function for `eth_getBlockReceipts`. /// diff --git a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs index 0e584de0dc36..90255c97741a 100644 --- a/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs +++ b/crates/rpc/rpc/src/eth/api/traits/blocking_task.rs @@ -12,7 +12,7 @@ pub trait SpawnBlocking: Clone + Send + Sync + 'static { /// Returns a handle for spawning IO heavy blocking tasks. /// /// Runtime access in default trait method implementations. - fn io_task_spawner(&self) -> &dyn TaskSpawner; + fn io_task_spawner(&self) -> impl TaskSpawner; /// Returns a handle for spawning CPU heavy blocking tasks. /// diff --git a/crates/rpc/rpc/src/eth/api/traits/state.rs b/crates/rpc/rpc/src/eth/api/traits/state.rs index 98359ef3fc71..ac80b88a01a3 100644 --- a/crates/rpc/rpc/src/eth/api/traits/state.rs +++ b/crates/rpc/rpc/src/eth/api/traits/state.rs @@ -20,7 +20,7 @@ pub trait EthState: LoadState + SpawnBlocking { /// Returns a handle for reading data from transaction pool. /// /// Data access in default trait method implementations. - fn pool(&self) -> &impl TransactionPool; + fn pool(&self) -> impl TransactionPool; /// Returns the number of transactions sent from an address at the given block identifier. /// @@ -133,11 +133,12 @@ pub trait EthState: LoadState + SpawnBlocking { } /// Loads state from database. +#[auto_impl::auto_impl(&, Arc)] pub trait LoadState { /// Returns a handle for reading state from database. /// /// Data access in default trait method implementations. - fn provider(&self) -> &impl StateProviderFactory; + fn provider(&self) -> impl StateProviderFactory; /// Returns the state at the given block number fn state_at_hash(&self, block_hash: B256) -> EthResult { diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 337d5da140a4..8786b32bb7df 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -75,7 +75,7 @@ pub trait EthTransactions: Send + Sync { /// Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. - fn provider(&self) -> &impl BlockReaderIdExt; + fn provider(&self) -> impl BlockReaderIdExt; /// Returns a handle for reading data from memory. /// diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index ca3ca029cea5..716c126ca682 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -66,7 +66,7 @@ where type Pool = Pool; #[inline] - fn provider(&self) -> &impl BlockReaderIdExt { + fn provider(&self) -> impl BlockReaderIdExt { self.inner.provider() } diff --git a/crates/storage/storage-api/src/receipts.rs b/crates/storage/storage-api/src/receipts.rs index b050ca3e248c..04eb81aad02d 100644 --- a/crates/storage/storage-api/src/receipts.rs +++ b/crates/storage/storage-api/src/receipts.rs @@ -38,6 +38,7 @@ pub trait ReceiptProvider: Send + Sync { /// so this trait can only be implemented for types that implement `BlockIdReader`. The /// `BlockIdReader` methods should be used to resolve `BlockId`s to block numbers or hashes, and /// retrieving the receipts should be done using the type's `ReceiptProvider` methods. +#[auto_impl::auto_impl(&, Arc)] pub trait ReceiptProviderIdExt: ReceiptProvider + BlockIdReader { /// Get receipt by block id fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult>> { diff --git a/crates/tasks/Cargo.toml b/crates/tasks/Cargo.toml index 63eb870fc15e..82c80c0932b8 100644 --- a/crates/tasks/Cargo.toml +++ b/crates/tasks/Cargo.toml @@ -23,6 +23,7 @@ reth-metrics.workspace = true metrics.workspace = true # misc +auto_impl.workspace = true tracing.workspace = true thiserror.workspace = true dyn-clone.workspace = true diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index ee5222e91312..d8bb4dd8889e 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -84,6 +84,7 @@ pub mod pool; /// ``` /// /// The [`TaskSpawner`] trait is [`DynClone`] so `Box` are also `Clone`. +#[auto_impl::auto_impl(&, Arc)] pub trait TaskSpawner: Send + Sync + Unpin + std::fmt::Debug + DynClone { /// Spawns the task onto the runtime. /// See also [`Handle::spawn`]. @@ -580,6 +581,7 @@ impl TaskSpawner for TaskExecutor { } /// `TaskSpawner` with extended behaviour +#[auto_impl::auto_impl(&, Arc)] pub trait TaskSpawnerExt: Send + Sync + Unpin + std::fmt::Debug + DynClone { /// This spawns a critical task onto the runtime. /// diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 41d57e94165e..e43c45e17e82 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -39,7 +39,7 @@ pub type PeerId = reth_primitives::B512; /// /// Note: This requires `Clone` for convenience, since it is assumed that this will be implemented /// for a wrapped `Arc` type, see also [`Pool`](crate::Pool). -#[auto_impl::auto_impl(Arc)] +#[auto_impl::auto_impl(&, Arc)] pub trait TransactionPool: Send + Sync + Clone { /// The transaction type of the pool type Transaction: PoolTransaction; @@ -388,7 +388,7 @@ pub trait TransactionPool: Send + Sync + Clone { } /// Extension for [TransactionPool] trait that allows to set the current block info. -#[auto_impl::auto_impl(Arc)] +#[auto_impl::auto_impl(&, Arc)] pub trait TransactionPoolExt: TransactionPool { /// Sets the current block info for the pool. fn set_block_info(&self, info: BlockInfo); From 9ec16f0c0125f11c44ed2e8573df22adfe76382b Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 16:22:39 +0200 Subject: [PATCH 30/33] Move RawTransactionForwarder into traits mod --- Cargo.lock | 1 + crates/rpc/rpc-builder/src/lib.rs | 2 +- crates/rpc/rpc/Cargo.toml | 1 + crates/rpc/rpc/src/eth/api/mod.rs | 5 +++-- crates/rpc/rpc/src/eth/api/traits/mod.rs | 2 +- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 12 ++++++++++-- crates/rpc/rpc/src/eth/api/transactions.rs | 4 ++-- crates/rpc/rpc/src/eth/mod.rs | 1 - crates/rpc/rpc/src/eth/traits.rs | 13 ------------- 9 files changed, 19 insertions(+), 22 deletions(-) delete mode 100644 crates/rpc/rpc/src/eth/traits.rs diff --git a/Cargo.lock b/Cargo.lock index fd8c646cff98..2e8ec4f6baba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7575,6 +7575,7 @@ dependencies = [ "alloy-sol-types", "assert_matches", "async-trait", + "auto_impl", "derive_more", "dyn-clone", "futures", diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index eae23b6b6c6d..3a25025861f8 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -180,10 +180,10 @@ use reth_provider::{ }; use reth_rpc::{ eth::{ + api::RawTransactionForwarder, cache::{cache_new_blocks_task, EthStateCache}, fee_history_cache_new_blocks_task, gas_oracle::GasPriceOracle, - traits::RawTransactionForwarder, EthBundle, FeeHistoryCache, }, AdminApi, DebugApi, EngineEthApi, EthApi, EthFilter, EthPubSub, EthSubscriptionIdProvider, diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index c005020c7ce0..dc62f8b9d93f 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -77,6 +77,7 @@ schnellru.workspace = true futures.workspace = true derive_more.workspace = true dyn-clone.workspace = true +auto_impl.workspace = true [dev-dependencies] reth-evm-ethereum.workspace = true diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 53ecdb52b3a7..d895f3920c35 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -45,10 +45,10 @@ mod state; pub mod traits; pub mod transactions; -use crate::eth::traits::RawTransactionForwarder; pub use receipt::ReceiptBuilder; pub use traits::{ - BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, SpawnBlocking, StateCacheDB, + BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, RawTransactionForwarder, + SpawnBlocking, StateCacheDB, }; pub use transactions::TransactionSource; @@ -56,6 +56,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 { /// Returns the current ethereum protocol version. async fn protocol_version(&self) -> RethResult; diff --git a/crates/rpc/rpc/src/eth/api/traits/mod.rs b/crates/rpc/rpc/src/eth/api/traits/mod.rs index 79f976922d07..caa4b4853340 100644 --- a/crates/rpc/rpc/src/eth/api/traits/mod.rs +++ b/crates/rpc/rpc/src/eth/api/traits/mod.rs @@ -10,4 +10,4 @@ pub use block::EthBlocks; pub use blocking_task::SpawnBlocking; pub use receipt::BuildReceipt; pub use state::{EthState, LoadState}; -pub use transaction::{EthTransactions, StateCacheDB}; +pub use transaction::{EthTransactions, RawTransactionForwarder, StateCacheDB}; diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 8786b32bb7df..24930da4de9d 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -1,7 +1,7 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. -use std::sync::Arc; +use std::{fmt, sync::Arc}; use reth_evm::ConfigureEvm; use reth_primitives::{ @@ -33,7 +33,6 @@ use crate::{ cache::EthStateCache, error::{EthApiError, EthResult}, revm_utils::{EvmOverrides, FillableTransaction}, - traits::RawTransactionForwarder, utils::recover_raw_transaction, TransactionSource, }, @@ -792,3 +791,12 @@ pub trait EthTransactions: Send + Sync { Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, R: Send + 'static; } + +/// A trait that allows for forwarding raw transactions. +/// +/// For example to a sequencer. +#[async_trait::async_trait] +pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static { + /// Forwards raw transaction bytes for `eth_sendRawTransaction` + async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>; +} diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 716c126ca682..28817ad4fc08 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -38,7 +38,7 @@ use crate::{ eth::{ api::{ pending_block::PendingBlockEnv, BuildReceipt, EthState, EthTransactions, LoadState, - SpawnBlocking, StateCacheDB, + RawTransactionForwarder, SpawnBlocking, StateCacheDB, }, cache::EthStateCache, error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, @@ -86,7 +86,7 @@ where } #[inline] - fn raw_tx_forwarder(&self) -> &Option> { + fn raw_tx_forwarder(&self) -> &Option> { self.inner.raw_tx_forwarder() } diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs index e0dc0cb47120..d596ee2a389e 100644 --- a/crates/rpc/rpc/src/eth/mod.rs +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -11,7 +11,6 @@ mod logs_utils; mod pubsub; pub mod revm_utils; mod signer; -pub mod traits; pub(crate) mod utils; pub use api::{ diff --git a/crates/rpc/rpc/src/eth/traits.rs b/crates/rpc/rpc/src/eth/traits.rs deleted file mode 100644 index 0f73ded3c82f..000000000000 --- a/crates/rpc/rpc/src/eth/traits.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Additional helper traits that allow for more customization. - -use crate::eth::error::EthResult; -use std::fmt; - -/// A trait that allows for forwarding raw transactions. -/// -/// For example to a sequencer. -#[async_trait::async_trait] -pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static { - /// Forwards raw transaction bytes for `eth_sendRawTransaction` - async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>; -} From 13edf49985782f42f67a89133a0f96506cd0266e Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 16:56:52 +0200 Subject: [PATCH 31/33] Fix merge conflicts --- crates/rpc/rpc/src/eth/api/mod.rs | 4 ++-- crates/rpc/rpc/src/eth/api/traits/transaction.rs | 4 ++-- crates/rpc/rpc/src/eth/api/transactions.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 420551189822..76204fde33b1 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -500,7 +500,7 @@ impl EthApiInner &Option> { - &self.raw_transaction_forwarder + pub fn raw_tx_forwarder(&self) -> Option> { + self.raw_transaction_forwarder.read().clone() } } diff --git a/crates/rpc/rpc/src/eth/api/traits/transaction.rs b/crates/rpc/rpc/src/eth/api/traits/transaction.rs index 24930da4de9d..d82ddead88d5 100644 --- a/crates/rpc/rpc/src/eth/api/traits/transaction.rs +++ b/crates/rpc/rpc/src/eth/api/traits/transaction.rs @@ -89,7 +89,7 @@ pub trait EthTransactions: Send + Sync { /// Returns a handle for forwarding received raw transactions. /// /// Access to transaction forwarder in default (L1) trait method implementations. - fn raw_tx_forwarder(&self) -> &Option>; + fn raw_tx_forwarder(&self) -> Option>; /// Returns a handle for reading evm config. /// @@ -447,7 +447,7 @@ pub trait EthTransactions: Send + Sync { async fn send_raw_transaction(&self, tx: Bytes) -> EthResult { // On optimism, transactions are forwarded directly to the sequencer to be included in // blocks that it builds. - if let Some(client) = self.raw_tx_forwarder().as_ref() { + if let Some(client) = self.raw_tx_forwarder() { tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); client.forward_raw_transaction(&tx).await?; } diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 28817ad4fc08..abb2a60d8511 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -86,7 +86,7 @@ where } #[inline] - fn raw_tx_forwarder(&self) -> &Option> { + fn raw_tx_forwarder(&self) -> Option> { self.inner.raw_tx_forwarder() } From 4b819783aa87ea74f404d3ba2b8bae90bed1298e Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 17:23:01 +0200 Subject: [PATCH 32/33] Fix lint --- crates/rpc/rpc/src/eth/api/block.rs | 15 +++++++-------- crates/rpc/rpc/src/eth/api/fees.rs | 18 ++++++++++-------- crates/rpc/rpc/src/eth/bundle.rs | 16 ++++++++-------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs index a28bd6a963d5..0fded533d74f 100644 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ b/crates/rpc/rpc/src/eth/api/block.rs @@ -1,10 +1,5 @@ //! Contains RPC handler implementations specific to blocks. -use crate::{ - eth::error::{EthApiError, EthResult}, - EthApi, -}; - use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; use reth_primitives::BlockId; @@ -16,9 +11,13 @@ 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 crate::eth::api::EthBlocks; - -use super::traits::LoadPendingBlock; +use crate::{ + eth::{ + api::{EthBlocks, LoadPendingBlock}, + error::{EthApiError, EthResult}, + }, + EthApi, +}; impl EthBlocks for EthApi where diff --git a/crates/rpc/rpc/src/eth/api/fees.rs b/crates/rpc/rpc/src/eth/api/fees.rs index 97bdd7a014bd..e67d5caaee1d 100644 --- a/crates/rpc/rpc/src/eth/api/fees.rs +++ b/crates/rpc/rpc/src/eth/api/fees.rs @@ -1,12 +1,5 @@ //! Contains RPC handler implementations for fee history. -use crate::{ - eth::{ - api::fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry}, - error::{EthApiError, EthResult}, - }, - EthApi, -}; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; use reth_primitives::{BlockNumberOrTag, U256}; @@ -15,7 +8,16 @@ use reth_rpc_types::FeeHistory; use reth_transaction_pool::TransactionPool; use tracing::debug; -use super::traits::LoadPendingBlock; +use crate::{ + eth::{ + api::{ + fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry}, + LoadPendingBlock, + }, + error::{EthApiError, EthResult}, + }, + EthApi, +}; impl EthApi where diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 494ba12629a3..6d07ba536ee2 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -1,11 +1,7 @@ //! `Eth` bundle implementation and helpers. -use crate::eth::{ - api::{EthTransactions, SpawnBlocking}, - error::{EthApiError, EthResult, RpcInvalidTransactionError}, - revm_utils::FillableTransaction, - utils::recover_raw_transaction, -}; +use std::sync::Arc; + use jsonrpsee::core::RpcResult; use reth_primitives::{ constants::eip4844::MAINNET_KZG_TRUSTED_SETUP, @@ -22,9 +18,13 @@ use revm::{ primitives::{ResultAndState, TxEnv}, }; use revm_primitives::{EnvWithHandlerCfg, MAX_BLOB_GAS_PER_BLOCK}; -use std::sync::Arc; -use super::api::LoadState; +use crate::eth::{ + api::{EthTransactions, LoadState, SpawnBlocking}, + error::{EthApiError, EthResult, RpcInvalidTransactionError}, + revm_utils::FillableTransaction, + utils::recover_raw_transaction, +}; /// `Eth` bundle implementation. pub struct EthBundle { From 008f939246e2336797688faad000f48b96a0fa79 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Sat, 8 Jun 2024 17:41:11 +0200 Subject: [PATCH 33/33] Fix lint --- crates/rpc/rpc/src/eth/bundle.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index a19cd082f3ad..6d07ba536ee2 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -26,8 +26,6 @@ use crate::eth::{ utils::recover_raw_transaction, }; -use super::api::LoadState; - /// `Eth` bundle implementation. pub struct EthBundle { /// All nested fields bundled together.