diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index 58d367012f..cec8672875 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -7,14 +7,16 @@ use futures::StreamExt; use op_alloy_consensus::{transaction::OpTransactionInfo, OpTransaction}; use reth_chain_state::CanonStateSubscriptions; use reth_optimism_primitives::DepositReceipt; -use reth_primitives_traits::{BlockBody, Recovered, SignedTransaction, WithEncoded}; +use reth_primitives_traits::{ + BlockBody, Recovered, SignedTransaction, SignerRecoverable, WithEncoded, +}; use reth_rpc_eth_api::{ - helpers::{spec::SignersForRpc, EthTransactions, LoadReceipt, LoadTransaction}, + helpers::{spec::SignersForRpc, EthTransactions, LoadReceipt, LoadTransaction, SpawnBlocking}, try_into_op_tx_info, EthApiTypes as _, FromEthApiError, FromEvmError, RpcConvert, RpcNodeCore, RpcReceipt, TxInfoMapper, }; -use reth_rpc_eth_types::EthApiError; -use reth_storage_api::{errors::ProviderError, ReceiptProvider}; +use reth_rpc_eth_types::{EthApiError, TransactionSource}; +use reth_storage_api::{errors::ProviderError, ProviderTx, ReceiptProvider, TransactionsProvider}; use reth_transaction_pool::{ AddedTransactionOutcome, PoolPooledTx, PoolTransaction, TransactionOrigin, TransactionPool, }; @@ -179,6 +181,53 @@ where OpEthApiError: FromEvmError, Rpc: RpcConvert, { + async fn transaction_by_hash( + &self, + hash: B256, + ) -> Result>>, Self::Error> { + // 1. Try to find the transaction on disk (historical blocks) + if let Some((tx, meta)) = self + .spawn_blocking_io(move |this| { + this.provider() + .transaction_by_hash_with_meta(hash) + .map_err(Self::Error::from_eth_err) + }) + .await? + { + let transaction = tx + .try_into_recovered_unchecked() + .map_err(|_| EthApiError::InvalidTransactionSignature)?; + + return Ok(Some(TransactionSource::Block { + transaction, + index: meta.index, + block_hash: meta.block_hash, + block_number: meta.block_number, + base_fee: meta.base_fee, + })); + } + + // 2. check flashblocks (sequencer preconfirmations) + if let Ok(Some(pending_block)) = self.pending_flashblock().await && + let Some(indexed_tx) = pending_block.block().find_indexed(hash) + { + let meta = indexed_tx.meta(); + return Ok(Some(TransactionSource::Block { + transaction: indexed_tx.recovered_tx().cloned(), + index: meta.index, + block_hash: meta.block_hash, + block_number: meta.block_number, + base_fee: meta.base_fee, + })); + } + + // 3. check local pool + if let Some(tx) = self.pool().get(&hash).map(|tx| tx.transaction.clone_into_consensus()) { + return Ok(Some(TransactionSource::Pool(tx))); + } + + Ok(None) + } } impl OpEthApi diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 2f6c3674ed..a6b7285d0c 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -609,45 +609,37 @@ pub trait LoadTransaction: SpawnBlocking + FullEthApiTypes + RpcNodeCoreExt { > + Send { async move { // Try to find the transaction on disk - let mut resp = self + if let Some((tx, meta)) = self .spawn_blocking_io(move |this| { - match this - .provider() + this.provider() .transaction_by_hash_with_meta(hash) - .map_err(Self::Error::from_eth_err)? - { - 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 - .try_into_recovered_unchecked() - .map_err(|_| 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)) - } - } + .map_err(Self::Error::from_eth_err) }) - .await?; + .await? + { + // 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 + .try_into_recovered_unchecked() + .map_err(|_| EthApiError::InvalidTransactionSignature)?; - if resp.is_none() { - // tx not found on disk, check pool - if let Some(tx) = - self.pool().get(&hash).map(|tx| tx.transaction.clone().into_consensus()) - { - resp = Some(TransactionSource::Pool(tx.into())); - } + return Ok(Some(TransactionSource::Block { + transaction, + index: meta.index, + block_hash: meta.block_hash, + block_number: meta.block_number, + base_fee: meta.base_fee, + })); } - Ok(resp) + // tx not found on disk, check pool + if let Some(tx) = self.pool().get(&hash).map(|tx| tx.transaction.clone_into_consensus()) + { + return Ok(Some(TransactionSource::Pool(tx.into()))); + } + + Ok(None) } }