Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify txpool.remove function #6641

Merged
merged 6 commits into from Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 5 additions & 14 deletions crates/transaction-pool/src/pool/pending.rs
Expand Up @@ -313,27 +313,18 @@ impl<T: TransactionOrdering> PendingPool<T> {
self.by_id.insert(tx_id, tx);
}

/// Removes a _mined_ transaction from the pool.
/// Removes the transaction from the pool.
///
/// If the transaction has a descendant transaction it will advance it to the best queue.
pub(crate) fn prune_transaction(
/// Note: If the transaction has a descendant transaction
/// it will advance it to the best queue.
pub(crate) fn remove_transaction(
&mut self,
id: &TransactionId,
) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
// mark the next as independent if it exists
if let Some(unlocked) = self.get(&id.descendant()) {
self.independent_transactions.insert(unlocked.clone());
};
self.remove_transaction(id)
}

/// Removes the transaction from the pool.
///
/// Note: this only removes the given transaction.
pub(crate) fn remove_transaction(
&mut self,
id: &TransactionId,
) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
}
let tx = self.by_id.remove(id)?;
self.size_of -= tx.transaction.size();
self.all.remove(&tx);
Expand Down
90 changes: 89 additions & 1 deletion crates/transaction-pool/src/pool/txpool.rs
Expand Up @@ -678,7 +678,7 @@ impl<T: TransactionOrdering> TxPool<T> {
tx: &TransactionId,
) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
match pool {
SubPool::Pending => self.pending_pool.prune_transaction(tx),
SubPool::Pending => self.pending_pool.remove_transaction(tx),
SubPool::Queued => self.queued_pool.remove_transaction(tx),
SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
SubPool::Blob => self.blob_pool.remove_transaction(tx),
Expand Down Expand Up @@ -2874,4 +2874,92 @@ mod tests {
assert!(pool.queued_transactions().is_empty());
assert_eq!(2, pool.pending_transactions().len());
}
#[test]
fn test_transaction_removal() {
let on_chain_balance = U256::from(10_000);
let on_chain_nonce = 0;
let mut f = MockTransactionFactory::default();
let mut pool = TxPool::new(MockOrdering::default(), Default::default());

let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
let tx_1 = tx_0.next();

// Create 2 transactions
let v0 = f.validated(tx_0.clone());
let v1 = f.validated(tx_1);

// Add them to the pool
let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
let _res = pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce).unwrap();

assert_eq!(0, pool.queued_transactions().len());
assert_eq!(2, pool.pending_transactions().len());

// Remove first (nonce 0) - simulating that it was taken to be a part of the block.
pool.remove_transaction(v0.id());
// assert the second transaction is really at the top of the queue
let pool_txs = pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>();
assert_eq!(vec![v1.nonce()], pool_txs);
}
#[test]
fn wrong_best_order_of_transactions() {
let on_chain_balance = U256::from(10_000);
let mut on_chain_nonce = 0;
let mut f = MockTransactionFactory::default();
let mut pool = TxPool::new(MockOrdering::default(), Default::default());

let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
let tx_1 = tx_0.next();
let tx_2 = tx_1.next();
let tx_3 = tx_2.next();

// Create 4 transactions
let v0 = f.validated(tx_0.clone());
let v1 = f.validated(tx_1);
let v2 = f.validated(tx_2);
let v3 = f.validated(tx_3);

// Add first 2 to the pool
let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
let _res = pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce).unwrap();

assert_eq!(0, pool.queued_transactions().len());
assert_eq!(2, pool.pending_transactions().len());

// Remove first (nonce 0) - simulating that it was taken to be a part of the block.
pool.remove_transaction(v0.id());

// Now add transaction with nonce 2
let _res = pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce).unwrap();

// v2 is in the queue now. v1 is still in 'pending'.
assert_eq!(1, pool.queued_transactions().len());
assert_eq!(1, pool.pending_transactions().len());

// Simulate new block arrival - and chain nonce increasing.
let mut updated_accounts = HashMap::new();
on_chain_nonce += 1;
updated_accounts.insert(
v0.sender_id(),
SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
);
pool.update_accounts(updated_accounts);

// Transactions are not changed (IMHO - this is a bug, as transaction v2 should be in the
// 'pending' now).
assert_eq!(0, pool.queued_transactions().len());
assert_eq!(2, pool.pending_transactions().len());

// Add transaction v3 - it 'unclogs' everything.
let _res = pool.add_transaction(v3.clone(), on_chain_balance, on_chain_nonce).unwrap();
assert_eq!(0, pool.queued_transactions().len());
assert_eq!(3, pool.pending_transactions().len());

// It should have returned transactions in order (v1, v2, v3 - as there is nothing blocking
// them).
assert_eq!(
pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>(),
vec![1, 2, 3]
);
}
loocapro marked this conversation as resolved.
Show resolved Hide resolved
}