mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-09 15:28:01 -05:00
feat(flashblock): Enable eth_getTransactionByHash support for flashblock (#19954)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -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<N::Evm>,
|
||||
Rpc: RpcConvert<Primitives = N::Primitives, Error = OpEthApiError>,
|
||||
{
|
||||
async fn transaction_by_hash(
|
||||
&self,
|
||||
hash: B256,
|
||||
) -> Result<Option<TransactionSource<ProviderTx<Self::Provider>>>, 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<N, Rpc> OpEthApi<N, Rpc>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user