fix(txpool): pending subpool basefee update (#4610)

This commit is contained in:
Roman Krasiuk
2023-09-15 15:47:54 +03:00
committed by GitHub
parent 455af5603b
commit 6b8db8ace4
2 changed files with 47 additions and 33 deletions

View File

@ -65,6 +65,19 @@ impl<T: TransactionOrdering> PendingPool<T> {
}
}
/// Clear all transactions from the pool without resetting other values.
/// Used for atomic reordering during basefee update.
///
/// # Returns
///
/// Returns all transactions by id.
fn clear_transactions(&mut self) -> BTreeMap<TransactionId, PendingTransaction<T>> {
self.independent_transactions.clear();
self.all.clear();
self.size_of.reset();
std::mem::take(&mut self.by_id)
}
/// Returns an iterator over all transactions that are _currently_ ready.
///
/// 1. The iterator _always_ returns transaction in order: It never returns a transaction with
@ -150,44 +163,38 @@ impl<T: TransactionOrdering> PendingPool<T> {
&mut self,
base_fee: u64,
) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
// Create a collection for txs to remove .
let mut to_remove = Vec::new();
// Create a collection for removed transactions.
let mut removed = Vec::new();
// Iterate over transactions, find the ones we need to remove and update others in place.
{
let mut iter = self.by_id.iter_mut().peekable();
while let Some((id, tx)) = iter.next() {
if tx.transaction.max_fee_per_gas() < base_fee as u128 {
// This transaction no longer satisfies the basefee: remove it and all its
// descendants.
to_remove.push(*id);
'this: while let Some((peek, _)) = iter.peek() {
if peek.sender != id.sender {
break 'this
}
to_remove.push(**peek);
iter.next();
// Drain and iterate over all transactions.
let mut transactions_iter = self.clear_transactions().into_iter().peekable();
while let Some((id, mut tx)) = transactions_iter.next() {
if tx.transaction.max_fee_per_gas() < base_fee as u128 {
// Add this tx to the removed collection since it no longer satisfies the base fee
// condition. Decrease the total pool size.
removed.push(Arc::clone(&tx.transaction));
// Remove all dependent transactions.
'this: while let Some((next_id, next_tx)) = transactions_iter.peek() {
if next_id.sender != id.sender {
break 'this
}
} else {
// Update the transaction with new priority.
let new_priority =
self.ordering.priority(&tx.transaction.transaction, base_fee);
tx.priority = new_priority;
self.all.insert(tx.clone());
removed.push(Arc::clone(&next_tx.transaction));
transactions_iter.next();
}
} else {
// Re-insert the transaction with new priority.
tx.priority = self.ordering.priority(&tx.transaction.transaction, base_fee);
self.size_of += tx.transaction.size();
if self.ancestor(&id).is_none() {
self.independent_transactions.insert(tx.clone());
}
self.all.insert(tx.clone());
self.by_id.insert(id, tx);
}
}
let mut removed = Vec::with_capacity(to_remove.len());
for id in to_remove {
removed.push(self.remove_transaction(&id).expect("transaction exists"));
}
// Clear ordered lists since the priority would be changed.
self.independent_transactions.clear();
self.all.clear();
removed
}
@ -261,8 +268,8 @@ impl<T: TransactionOrdering> PendingPool<T> {
id: &TransactionId,
) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
let tx = self.by_id.remove(id)?;
self.all.remove(&tx);
self.size_of -= tx.transaction.size();
self.all.remove(&tx);
self.independent_transactions.remove(&tx);
Some(tx.transaction)
}

View File

@ -10,6 +10,13 @@ use std::ops::{AddAssign, SubAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct SizeTracker(isize);
impl SizeTracker {
/// Reset the size tracker.
pub fn reset(&mut self) {
self.0 = 0;
}
}
impl AddAssign<usize> for SizeTracker {
fn add_assign(&mut self, rhs: usize) {
self.0 += rhs as isize