mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 09:08:05 -05:00
fix: fetch 4844 blob before reinjected reorged blob txs (#5460)
This commit is contained in:
@@ -734,7 +734,7 @@ where
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
// this is a new transaction that should be imported into the pool
|
||||
let pool_transaction = <Pool::Transaction as FromRecoveredPooledTransaction>::from_recovered_transaction(tx);
|
||||
let pool_transaction = <Pool::Transaction as FromRecoveredPooledTransaction>::from_recovered_pooled_transaction(tx);
|
||||
|
||||
let pool = self.pool.clone();
|
||||
|
||||
|
||||
@@ -1484,7 +1484,7 @@ impl FromRecoveredTransaction for TransactionSignedEcRecovered {
|
||||
#[cfg(feature = "c-kzg")]
|
||||
pub trait FromRecoveredPooledTransaction {
|
||||
/// Converts to this type from the given [`PooledTransactionsElementEcRecovered`].
|
||||
fn from_recovered_transaction(tx: PooledTransactionsElementEcRecovered) -> Self;
|
||||
fn from_recovered_pooled_transaction(tx: PooledTransactionsElementEcRecovered) -> Self;
|
||||
}
|
||||
|
||||
/// The inverse of [`FromRecoveredTransaction`] that ensure the transaction can be sent over the
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#![cfg_attr(docsrs, doc(cfg(feature = "c-kzg")))]
|
||||
|
||||
use crate::{
|
||||
Address, BlobTransaction, Bytes, Signature, Transaction, TransactionSigned,
|
||||
TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxHash, TxLegacy, B256, EIP4844_TX_TYPE_ID,
|
||||
Address, BlobTransaction, BlobTransactionSidecar, Bytes, Signature, Transaction,
|
||||
TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxHash, TxLegacy, B256,
|
||||
EIP4844_TX_TYPE_ID,
|
||||
};
|
||||
use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE};
|
||||
use bytes::Buf;
|
||||
@@ -71,6 +72,27 @@ impl PooledTransactionsElement {
|
||||
Ok(tx.into())
|
||||
}
|
||||
|
||||
/// Converts from an EIP-4844 [TransactionSignedEcRecovered] to a
|
||||
/// [PooledTransactionsElementEcRecovered] with the given sidecar.
|
||||
///
|
||||
/// Returns the transaction is not an EIP-4844 transaction.
|
||||
pub fn try_from_blob_transaction(
|
||||
tx: TransactionSigned,
|
||||
sidecar: BlobTransactionSidecar,
|
||||
) -> Result<Self, TransactionSigned> {
|
||||
let TransactionSigned { transaction, signature, hash } = tx;
|
||||
if let Transaction::Eip4844(tx) = transaction {
|
||||
Ok(PooledTransactionsElement::BlobTransaction(BlobTransaction {
|
||||
transaction: tx,
|
||||
signature,
|
||||
hash,
|
||||
sidecar,
|
||||
}))
|
||||
} else {
|
||||
Err(TransactionSigned { transaction, signature, hash })
|
||||
}
|
||||
}
|
||||
|
||||
/// Heavy operation that return signature hash over rlp encoded transaction.
|
||||
/// It is only for signature signing or signer recovery.
|
||||
pub fn signature_hash(&self) -> B256 {
|
||||
@@ -575,6 +597,21 @@ impl PooledTransactionsElementEcRecovered {
|
||||
) -> Self {
|
||||
Self { transaction, signer }
|
||||
}
|
||||
|
||||
/// Converts from an EIP-4844 [TransactionSignedEcRecovered] to a
|
||||
/// [PooledTransactionsElementEcRecovered] with the given sidecar.
|
||||
///
|
||||
/// Returns the transaction is not an EIP-4844 transaction.
|
||||
pub fn try_from_blob_transaction(
|
||||
tx: TransactionSignedEcRecovered,
|
||||
sidecar: BlobTransactionSidecar,
|
||||
) -> Result<Self, TransactionSignedEcRecovered> {
|
||||
let TransactionSignedEcRecovered { signer, signed_transaction } = tx;
|
||||
let transaction =
|
||||
PooledTransactionsElement::try_from_blob_transaction(signed_transaction, sidecar)
|
||||
.map_err(|tx| TransactionSignedEcRecovered { signer, signed_transaction: tx })?;
|
||||
Ok(Self { transaction, signer })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionSignedEcRecovered> for PooledTransactionsElementEcRecovered {
|
||||
|
||||
@@ -491,7 +491,7 @@ where
|
||||
self.forward_to_sequencer(&tx).await?;
|
||||
|
||||
let recovered = recover_raw_transaction(tx)?;
|
||||
let pool_transaction = <Pool::Transaction>::from_recovered_transaction(recovered);
|
||||
let pool_transaction = <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?;
|
||||
@@ -578,7 +578,8 @@ where
|
||||
let recovered =
|
||||
signed_tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?;
|
||||
|
||||
let pool_transaction = <Pool::Transaction>::from_recovered_transaction(recovered.into());
|
||||
let pool_transaction =
|
||||
<Pool::Transaction>::from_recovered_pooled_transaction(recovered.into());
|
||||
|
||||
// submit the transaction to the pool with a `Local` origin
|
||||
let hash = self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?;
|
||||
|
||||
@@ -12,7 +12,8 @@ use futures_util::{
|
||||
};
|
||||
use reth_interfaces::RethError;
|
||||
use reth_primitives::{
|
||||
Address, BlockHash, BlockNumber, BlockNumberOrTag, FromRecoveredTransaction,
|
||||
Address, BlockHash, BlockNumber, BlockNumberOrTag, FromRecoveredPooledTransaction,
|
||||
FromRecoveredTransaction, PooledTransactionsElementEcRecovered,
|
||||
};
|
||||
use reth_provider::{
|
||||
BlockReaderIdExt, BundleStateWithReceipts, CanonStateNotification, ChainSpecProvider,
|
||||
@@ -286,7 +287,31 @@ pub async fn maintain_transaction_pool<Client, P, St, Tasks>(
|
||||
let pruned_old_transactions = old_blocks
|
||||
.transactions_ecrecovered()
|
||||
.filter(|tx| !new_mined_transactions.contains(&tx.hash))
|
||||
.map(<P as TransactionPool>::Transaction::from_recovered_transaction)
|
||||
.filter_map(|tx| {
|
||||
if tx.is_eip4844() {
|
||||
// reorged blobs no longer include the blob, which is necessary for
|
||||
// validating the transaction. Even though the transaction could have
|
||||
// been validated previously, we still need the blob in order to
|
||||
// accurately set the transaction's
|
||||
// encoded-length which is propagated over the network.
|
||||
pool.get_blob(tx.hash)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|sidecar| {
|
||||
PooledTransactionsElementEcRecovered::try_from_blob_transaction(
|
||||
tx, sidecar,
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map(
|
||||
<P as TransactionPool>::Transaction::from_recovered_pooled_transaction,
|
||||
)
|
||||
} else {
|
||||
Some(<P as TransactionPool>::Transaction::from_recovered_transaction(
|
||||
tx,
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// update the pool first
|
||||
|
||||
@@ -778,7 +778,7 @@ impl FromRecoveredTransaction for MockTransaction {
|
||||
}
|
||||
|
||||
impl FromRecoveredPooledTransaction for MockTransaction {
|
||||
fn from_recovered_transaction(tx: PooledTransactionsElementEcRecovered) -> Self {
|
||||
fn from_recovered_pooled_transaction(tx: PooledTransactionsElementEcRecovered) -> Self {
|
||||
FromRecoveredTransaction::from_recovered_transaction(tx.into_ecrecovered_transaction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -921,6 +921,10 @@ impl PoolTransaction for EthPooledTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
fn access_list(&self) -> Option<&AccessList> {
|
||||
self.transaction.access_list()
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 Priority fee the caller is paying to the block author.
|
||||
///
|
||||
/// This will return `None` for non-EIP1559 transactions
|
||||
@@ -939,10 +943,6 @@ impl PoolTransaction for EthPooledTransaction {
|
||||
self.transaction.max_fee_per_blob_gas()
|
||||
}
|
||||
|
||||
fn access_list(&self) -> Option<&AccessList> {
|
||||
self.transaction.access_list()
|
||||
}
|
||||
|
||||
/// Returns the effective tip for this transaction.
|
||||
///
|
||||
/// For EIP-1559 transactions: `min(max_fee_per_gas - base_fee, max_priority_fee_per_gas)`.
|
||||
@@ -1029,7 +1029,7 @@ impl FromRecoveredTransaction for EthPooledTransaction {
|
||||
}
|
||||
|
||||
impl FromRecoveredPooledTransaction for EthPooledTransaction {
|
||||
fn from_recovered_transaction(tx: PooledTransactionsElementEcRecovered) -> Self {
|
||||
fn from_recovered_pooled_transaction(tx: PooledTransactionsElementEcRecovered) -> Self {
|
||||
EthPooledTransaction::from(tx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,8 +771,9 @@ mod tests {
|
||||
let data = hex::decode(raw).unwrap();
|
||||
let tx = PooledTransactionsElement::decode_enveloped(data.into()).unwrap();
|
||||
|
||||
let transaction =
|
||||
EthPooledTransaction::from_recovered_transaction(tx.try_into_ecrecovered().unwrap());
|
||||
let transaction = EthPooledTransaction::from_recovered_pooled_transaction(
|
||||
tx.try_into_ecrecovered().unwrap(),
|
||||
);
|
||||
let res = ensure_intrinsic_gas(&transaction, false);
|
||||
assert!(res.is_ok());
|
||||
let res = ensure_intrinsic_gas(&transaction, true);
|
||||
|
||||
Reference in New Issue
Block a user