mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
feat: add BestTransactionsWithAttributes blob fee checks (#6674)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -17,13 +17,14 @@ use tracing::debug;
|
||||
///
|
||||
/// This is a wrapper around [`BestTransactions`] that also enforces a specific basefee.
|
||||
///
|
||||
/// This iterator guarantees that all transaction it returns satisfy the base fee.
|
||||
pub(crate) struct BestTransactionsWithBasefee<T: TransactionOrdering> {
|
||||
/// This iterator guarantees that all transaction it returns satisfy both the base fee and blob fee!
|
||||
pub(crate) struct BestTransactionsWithFees<T: TransactionOrdering> {
|
||||
pub(crate) best: BestTransactions<T>,
|
||||
pub(crate) base_fee: u64,
|
||||
pub(crate) base_fee_per_blob_gas: u64,
|
||||
}
|
||||
|
||||
impl<T: TransactionOrdering> crate::traits::BestTransactions for BestTransactionsWithBasefee<T> {
|
||||
impl<T: TransactionOrdering> crate::traits::BestTransactions for BestTransactionsWithFees<T> {
|
||||
fn mark_invalid(&mut self, tx: &Self::Item) {
|
||||
BestTransactions::mark_invalid(&mut self.best, tx)
|
||||
}
|
||||
@ -41,7 +42,7 @@ impl<T: TransactionOrdering> crate::traits::BestTransactions for BestTransaction
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransactionOrdering> Iterator for BestTransactionsWithBasefee<T> {
|
||||
impl<T: TransactionOrdering> Iterator for BestTransactionsWithFees<T> {
|
||||
type Item = Arc<ValidPoolTransaction<T::Transaction>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -52,6 +53,13 @@ impl<T: TransactionOrdering> Iterator for BestTransactionsWithBasefee<T> {
|
||||
// tx violates base fee, mark it as invalid and continue
|
||||
crate::traits::BestTransactions::mark_invalid(self, &best);
|
||||
} else {
|
||||
// tx is EIP4844 and violates blob fee, mark it as invalid and continue
|
||||
if best.transaction.max_fee_per_blob_gas().is_some_and(|max_fee_per_blob_gas| {
|
||||
max_fee_per_blob_gas < self.base_fee_per_blob_gas as u128
|
||||
}) {
|
||||
crate::traits::BestTransactions::mark_invalid(self, &best);
|
||||
continue;
|
||||
};
|
||||
return Some(best)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,12 +80,42 @@ impl<T: PoolTransaction> BlobTransactions<T> {
|
||||
Some(tx.transaction)
|
||||
}
|
||||
|
||||
/// Returns all transactions that satisfy the given basefee and blob_fee.
|
||||
pub(crate) const fn satisfy_attributes(
|
||||
/// Returns all transactions that satisfy the given basefee and blobfee.
|
||||
///
|
||||
/// Note: This does not remove any the transactions from the pool.
|
||||
pub(crate) fn satisfy_attributes(
|
||||
&self,
|
||||
_best_transactions_attributes: BestTransactionsAttributes,
|
||||
best_transactions_attributes: BestTransactionsAttributes,
|
||||
) -> Vec<Arc<ValidPoolTransaction<T>>> {
|
||||
Vec::new()
|
||||
let mut transactions = Vec::new();
|
||||
{
|
||||
// short path if blob_fee is None in provided best transactions attributes
|
||||
if let Some(blob_fee_to_satisfy) =
|
||||
best_transactions_attributes.blob_fee.map(|fee| fee as u128)
|
||||
{
|
||||
let mut iter = self.by_id.iter().peekable();
|
||||
|
||||
while let Some((id, tx)) = iter.next() {
|
||||
if tx.transaction.max_fee_per_blob_gas().unwrap_or_default() <
|
||||
blob_fee_to_satisfy ||
|
||||
tx.transaction.max_fee_per_gas() <
|
||||
best_transactions_attributes.basefee as u128
|
||||
{
|
||||
// does not satisfy the blob fee or base fee
|
||||
// still parked in blob pool -> skip descendant transactions
|
||||
'this: while let Some((peek, _)) = iter.peek() {
|
||||
if peek.sender != id.sender {
|
||||
break 'this
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
} else {
|
||||
transactions.push(tx.transaction.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transactions
|
||||
}
|
||||
|
||||
/// Returns true if the pool exceeds the given limit
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
identifier::{SenderId, TransactionId},
|
||||
pool::{
|
||||
best::{BestTransactions, BestTransactionsWithBasefee},
|
||||
best::{BestTransactions, BestTransactionsWithFees},
|
||||
size::SizeTracker,
|
||||
},
|
||||
Priority, SubPoolLimit, TransactionOrdering, ValidPoolTransaction,
|
||||
@ -115,9 +115,13 @@ impl<T: TransactionOrdering> PendingPool<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `best` but only returns transactions that satisfy the given basefee.
|
||||
pub(crate) fn best_with_basefee(&self, base_fee: u64) -> BestTransactionsWithBasefee<T> {
|
||||
BestTransactionsWithBasefee { best: self.best(), base_fee }
|
||||
/// Same as `best` but only returns transactions that satisfy the given basefee and blobfee.
|
||||
pub(crate) fn best_with_basefee_and_blobfee(
|
||||
&self,
|
||||
base_fee: u64,
|
||||
base_fee_per_blob_gas: u64,
|
||||
) -> BestTransactionsWithFees<T> {
|
||||
BestTransactionsWithFees { best: self.best(), base_fee, base_fee_per_blob_gas }
|
||||
}
|
||||
|
||||
/// Same as `best` but also includes the given unlocked transactions.
|
||||
|
||||
@ -287,38 +287,67 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator that yields transactions that are ready to be included in the block.
|
||||
/// Returns an iterator that yields transactions that are ready to be included in the block with
|
||||
/// the tracked fees.
|
||||
pub(crate) fn best_transactions(&self) -> BestTransactions<T> {
|
||||
self.pending_pool.best()
|
||||
}
|
||||
|
||||
/// Returns an iterator that yields transactions that are ready to be included in the block with
|
||||
/// the given base fee and optional blob fee.
|
||||
///
|
||||
/// If the provided attributes differ from the currently tracked fees, this will also include
|
||||
/// transactions that are unlocked by the new fees, or exclude transactions that are no longer
|
||||
/// valid with the new fees.
|
||||
pub(crate) fn best_transactions_with_attributes(
|
||||
&self,
|
||||
best_transactions_attributes: BestTransactionsAttributes,
|
||||
) -> Box<dyn crate::traits::BestTransactions<Item = Arc<ValidPoolTransaction<T::Transaction>>>>
|
||||
{
|
||||
// First we need to check if the given base fee is different than what's currently being
|
||||
// tracked
|
||||
match best_transactions_attributes.basefee.cmp(&self.all_transactions.pending_fees.base_fee)
|
||||
{
|
||||
Ordering::Equal => {
|
||||
// fee unchanged, nothing to shift
|
||||
Box::new(self.best_transactions())
|
||||
// for EIP-4844 transactions we also need to check if the blob fee is now lower than
|
||||
// what's currently being tracked, if so we need to include transactions from the
|
||||
// blob pool that are valid with the lower blob fee
|
||||
if best_transactions_attributes
|
||||
.blob_fee
|
||||
.map_or(false, |fee| fee < self.all_transactions.pending_fees.blob_fee as u64)
|
||||
{
|
||||
let unlocked_by_blob_fee =
|
||||
self.blob_pool.satisfy_attributes(best_transactions_attributes);
|
||||
|
||||
Box::new(self.pending_pool.best_with_unlocked(
|
||||
unlocked_by_blob_fee,
|
||||
self.all_transactions.pending_fees.base_fee,
|
||||
))
|
||||
} else {
|
||||
Box::new(self.pending_pool.best())
|
||||
}
|
||||
}
|
||||
Ordering::Greater => {
|
||||
// base fee increased, we only need to enforce this on the pending pool
|
||||
Box::new(self.pending_pool.best_with_basefee(best_transactions_attributes.basefee))
|
||||
Box::new(self.pending_pool.best_with_basefee_and_blobfee(
|
||||
best_transactions_attributes.basefee,
|
||||
best_transactions_attributes.blob_fee.unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Ordering::Less => {
|
||||
// base fee decreased, we need to move transactions from the basefee pool to the
|
||||
// pending pool and satisfy blob fee transactions as well
|
||||
let unlocked_with_blob =
|
||||
self.blob_pool.satisfy_attributes(best_transactions_attributes);
|
||||
// base fee decreased, we need to move transactions from the basefee + blob pool to
|
||||
// the pending pool that might be unlocked by the lower base fee
|
||||
let mut unlocked = self
|
||||
.basefee_pool
|
||||
.satisfy_base_fee_transactions(best_transactions_attributes.basefee);
|
||||
|
||||
Box::new(self.pending_pool.best_with_unlocked(
|
||||
unlocked_with_blob,
|
||||
self.all_transactions.pending_fees.base_fee,
|
||||
))
|
||||
// also include blob pool transactions that are now unlocked
|
||||
unlocked.extend(self.blob_pool.satisfy_attributes(best_transactions_attributes));
|
||||
|
||||
Box::new(
|
||||
self.pending_pool
|
||||
.best_with_unlocked(unlocked, self.all_transactions.pending_fees.base_fee),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user