From 4cd714e8d8913c475488be9ee445cde5e3aa5c55 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 2 May 2025 10:41:11 +0200 Subject: [PATCH] chore(op-sdk): Relax trait bounds on `TraceApi` methods not accessing mempool (#15752) --- crates/optimism/rpc/src/eth/block.rs | 9 +- crates/rpc/rpc-eth-api/src/helpers/block.rs | 13 +- .../rpc-eth-api/src/helpers/pending_block.rs | 5 +- crates/rpc/rpc/src/eth/helpers/block.rs | 11 +- crates/rpc/rpc/src/trace.rs | 222 +++++++++--------- 5 files changed, 148 insertions(+), 112 deletions(-) diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index 7a87ea4d53..67211e9d53 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -12,7 +12,8 @@ use reth_rpc_eth_api::{ types::RpcTypes, RpcReceipt, }; -use reth_storage_api::{BlockReader, HeaderProvider}; +use reth_storage_api::{BlockReader, HeaderProvider, ProviderTx}; +use reth_transaction_pool::{PoolTransaction, TransactionPool}; use crate::{eth::OpNodeCore, OpEthApi, OpEthApiError, OpReceiptBuilder}; @@ -83,7 +84,11 @@ where impl LoadBlock for OpEthApi where - Self: LoadPendingBlock + SpawnBlocking, + Self: LoadPendingBlock< + Pool: TransactionPool< + Transaction: PoolTransaction>, + >, + > + SpawnBlocking, N: OpNodeCore, { } diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs index 5bdab4ed35..b88bd9b65c 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -13,9 +13,10 @@ use futures::Future; use reth_node_api::BlockBody; use reth_primitives_traits::{RecoveredBlock, SealedBlock}; use reth_provider::{ - BlockIdReader, BlockReader, BlockReaderIdExt, ProviderHeader, ProviderReceipt, + BlockIdReader, BlockReader, BlockReaderIdExt, ProviderHeader, ProviderReceipt, ProviderTx, }; use reth_rpc_types_compat::block::from_block; +use reth_transaction_pool::{PoolTransaction, TransactionPool}; use std::sync::Arc; /// Result type of the fetched block receipts. @@ -116,6 +117,8 @@ pub trait EthBlocks: LoadBlock { ) -> impl Future> + Send where Self: LoadReceipt, + Self::Pool: + TransactionPool>>, { async move { if block_id.is_pending() { @@ -199,7 +202,13 @@ pub trait EthBlocks: LoadBlock { /// Loads a block from database. /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. -pub trait LoadBlock: LoadPendingBlock + SpawnBlocking + RpcNodeCoreExt { +pub trait LoadBlock: + LoadPendingBlock + + SpawnBlocking + + RpcNodeCoreExt< + Pool: TransactionPool>>, + > +{ /// Returns the block object for the given block id. #[expect(clippy::type_complexity)] fn recovered_block( diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index daca9ba46f..b8c682651f 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -45,7 +45,6 @@ pub trait LoadPendingBlock: Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory, - Pool: TransactionPool>>, Evm: ConfigureEvm< Primitives: NodePrimitives< BlockHeader = ProviderHeader, @@ -136,6 +135,8 @@ pub trait LoadPendingBlock: > + Send where Self: SpawnBlocking, + Self::Pool: + TransactionPool>>, { async move { let pending = self.pending_block_env_and_cfg()?; @@ -203,6 +204,8 @@ pub trait LoadPendingBlock: Self::Error, > where + Self::Pool: + TransactionPool>>, EthApiError: From, { let state_provider = self diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs index d57f26c1e1..6304b73dcc 100644 --- a/crates/rpc/rpc/src/eth/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -10,7 +10,8 @@ use reth_rpc_eth_api::{ RpcNodeCoreExt, RpcReceipt, }; use reth_rpc_eth_types::{EthApiError, EthReceiptBuilder}; -use reth_storage_api::BlockReader; +use reth_storage_api::{BlockReader, ProviderTx}; +use reth_transaction_pool::{PoolTransaction, TransactionPool}; use crate::EthApi; @@ -70,7 +71,13 @@ where impl LoadBlock for EthApi where - Self: LoadPendingBlock + SpawnBlocking + RpcNodeCoreExt, + Self: LoadPendingBlock + + SpawnBlocking + + RpcNodeCoreExt< + Pool: TransactionPool< + Transaction: PoolTransaction>, + >, + >, Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index ecdca8a12b..a2c621045d 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -20,7 +20,10 @@ use reth_evm::ConfigureEvm; use reth_primitives_traits::{BlockBody, BlockHeader}; use reth_revm::{database::StateProviderDatabase, db::CacheDB}; use reth_rpc_api::TraceApiServer; -use reth_rpc_eth_api::{helpers::TraceExt, FromEthApiError, RpcNodeCore}; +use reth_rpc_eth_api::{ + helpers::{Call, LoadPendingBlock, LoadTransaction, Trace, TraceExt}, + FromEthApiError, RpcNodeCore, +}; use reth_rpc_eth_types::{error::EthApiError, utils::recover_raw_transaction, EthConfig}; use reth_storage_api::{BlockNumReader, BlockReader}; use reth_tasks::pool::BlockingTaskGuard; @@ -73,11 +76,13 @@ impl TraceApi { } } -// === impl TraceApi === +// === impl TraceApi === // impl TraceApi where - Eth: TraceExt + 'static, + // tracing methods do _not_ read from mempool, hence no `LoadBlock` trait + // bound + Eth: Trace + Call + LoadPendingBlock + LoadTransaction + 'static, { /// Executes the given call and returns a number of possible traces for it. pub async fn trace_call( @@ -234,6 +239,115 @@ where Ok(self.trace_transaction(hash).await?.and_then(|traces| traces.into_iter().nth(index))) } + /// Returns all traces for the given transaction hash + pub async fn trace_transaction( + &self, + hash: B256, + ) -> Result>, Eth::Error> { + self.eth_api() + .spawn_trace_transaction_in_block( + hash, + TracingInspectorConfig::default_parity(), + move |tx_info, inspector, _, _| { + let traces = + inspector.into_parity_builder().into_localized_transaction_traces(tx_info); + Ok(traces) + }, + ) + .await + } + + /// Returns all opcodes with their count and combined gas usage for the given transaction in no + /// particular order. + pub async fn trace_transaction_opcode_gas( + &self, + tx_hash: B256, + ) -> Result, Eth::Error> { + self.eth_api() + .spawn_trace_transaction_in_block_with_inspector( + tx_hash, + OpcodeGasInspector::default(), + move |_tx_info, inspector, _res, _| { + let trace = TransactionOpcodeGas { + transaction_hash: tx_hash, + opcode_gas: inspector.opcode_gas_iter().collect(), + }; + Ok(trace) + }, + ) + .await + } + + /// Calculates the base block reward for the given block: + /// + /// - if Paris hardfork is activated, no block rewards are given + /// - if Paris hardfork is not activated, calculate block rewards with block number only + /// - if Paris hardfork is unknown, calculate block rewards with block number and ttd + fn calculate_base_block_reward( + &self, + header: &H, + ) -> Result, Eth::Error> { + let chain_spec = self.provider().chain_spec(); + let is_paris_activated = if chain_spec.chain() == MAINNET.chain() { + Some(header.number()) >= EthereumHardfork::Paris.mainnet_activation_block() + } else if chain_spec.chain() == SEPOLIA.chain() { + Some(header.number()) >= EthereumHardfork::Paris.sepolia_activation_block() + } else { + true + }; + + if is_paris_activated { + return Ok(None) + } + + Ok(Some(base_block_reward_pre_merge(&chain_spec, header.number()))) + } + + /// Extracts the reward traces for the given block: + /// - block reward + /// - uncle rewards + fn extract_reward_traces( + &self, + header: &H, + ommers: Option<&[H]>, + base_block_reward: u128, + ) -> Vec { + let ommers_cnt = ommers.map(|o| o.len()).unwrap_or_default(); + let mut traces = Vec::with_capacity(ommers_cnt + 1); + + let block_reward = block_reward(base_block_reward, ommers_cnt); + traces.push(reward_trace( + header, + RewardAction { + author: header.beneficiary(), + reward_type: RewardType::Block, + value: U256::from(block_reward), + }, + )); + + let Some(ommers) = ommers else { return traces }; + + for uncle in ommers { + let uncle_reward = ommer_reward(base_block_reward, header.number(), uncle.number()); + traces.push(reward_trace( + header, + RewardAction { + author: uncle.beneficiary(), + reward_type: RewardType::Uncle, + value: U256::from(uncle_reward), + }, + )); + } + traces + } +} + +impl TraceApi +where + // tracing methods read from mempool, hence `LoadBlock` trait bound via + // `TraceExt` + Eth: TraceExt + 'static, +{ /// Returns all transaction traces that match the given filter. /// /// This is similar to [`Self::trace_block`] but only returns traces for transactions that match @@ -346,24 +460,6 @@ where Ok(all_traces) } - /// Returns all traces for the given transaction hash - pub async fn trace_transaction( - &self, - hash: B256, - ) -> Result>, Eth::Error> { - self.eth_api() - .spawn_trace_transaction_in_block( - hash, - TracingInspectorConfig::default_parity(), - move |tx_info, inspector, _, _| { - let traces = - inspector.into_parity_builder().into_localized_transaction_traces(tx_info); - Ok(traces) - }, - ) - .await - } - /// Returns traces created at given block. pub async fn trace_block( &self, @@ -431,27 +527,6 @@ where .await } - /// Returns all opcodes with their count and combined gas usage for the given transaction in no - /// particular order. - pub async fn trace_transaction_opcode_gas( - &self, - tx_hash: B256, - ) -> Result, Eth::Error> { - self.eth_api() - .spawn_trace_transaction_in_block_with_inspector( - tx_hash, - OpcodeGasInspector::default(), - move |_tx_info, inspector, _res, _| { - let trace = TransactionOpcodeGas { - transaction_hash: tx_hash, - opcode_gas: inspector.opcode_gas_iter().collect(), - }; - Ok(trace) - }, - ) - .await - } - /// Returns the opcodes of all transactions in the given block. /// /// This is the same as [`Self::trace_transaction_opcode_gas`] but for all transactions in a @@ -486,69 +561,6 @@ where transactions, })) } - - /// Calculates the base block reward for the given block: - /// - /// - if Paris hardfork is activated, no block rewards are given - /// - if Paris hardfork is not activated, calculate block rewards with block number only - /// - if Paris hardfork is unknown, calculate block rewards with block number and ttd - fn calculate_base_block_reward( - &self, - header: &H, - ) -> Result, Eth::Error> { - let chain_spec = self.provider().chain_spec(); - let is_paris_activated = if chain_spec.chain() == MAINNET.chain() { - Some(header.number()) >= EthereumHardfork::Paris.mainnet_activation_block() - } else if chain_spec.chain() == SEPOLIA.chain() { - Some(header.number()) >= EthereumHardfork::Paris.sepolia_activation_block() - } else { - true - }; - - if is_paris_activated { - return Ok(None) - } - - Ok(Some(base_block_reward_pre_merge(&chain_spec, header.number()))) - } - - /// Extracts the reward traces for the given block: - /// - block reward - /// - uncle rewards - fn extract_reward_traces( - &self, - header: &H, - ommers: Option<&[H]>, - base_block_reward: u128, - ) -> Vec { - let ommers_cnt = ommers.map(|o| o.len()).unwrap_or_default(); - let mut traces = Vec::with_capacity(ommers_cnt + 1); - - let block_reward = block_reward(base_block_reward, ommers_cnt); - traces.push(reward_trace( - header, - RewardAction { - author: header.beneficiary(), - reward_type: RewardType::Block, - value: U256::from(block_reward), - }, - )); - - let Some(ommers) = ommers else { return traces }; - - for uncle in ommers { - let uncle_reward = ommer_reward(base_block_reward, header.number(), uncle.number()); - traces.push(reward_trace( - header, - RewardAction { - author: uncle.beneficiary(), - reward_type: RewardType::Uncle, - value: U256::from(uncle_reward), - }, - )); - } - traces - } } #[async_trait]