fix: fetch 4844 blob before reinjected reorged blob txs (#5460)

This commit is contained in:
Matthias Seitz
2023-11-16 19:54:07 +01:00
committed by GitHub
parent ec3dbfe995
commit 2b4eb8438c
8 changed files with 80 additions and 16 deletions

View File

@@ -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();

View File

@@ -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

View File

@@ -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 {

View File

@@ -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?;

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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)
}
}

View File

@@ -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);