docs(txpool): update BestTransaction docs (#57)

This commit is contained in:
Matthias Seitz
2022-10-13 19:44:18 +02:00
committed by GitHub
parent 74b04dc81a
commit 577e840062
2 changed files with 84 additions and 3 deletions

View File

@ -10,10 +10,23 @@ use std::{
};
use tracing::debug;
/// An iterator that returns transactions that can be executed on the current state.
/// An iterator that returns transactions that can be executed on the current state (*best*
/// transactions).
///
/// The [`PendingPool`] contains transactions that *could* all be executed on the current state, but
/// only yields transactions that are ready to be executed now.
/// While it contains all gapless transactions of a sender, it _always_ only returns the transaction
/// with the current on chain nonce.
pub struct BestTransactions<T: TransactionOrdering> {
/// Contains a copy of _all_ transactions of the pending pool at the point in time this
/// iterator was created.
pub(crate) all: BTreeMap<TransactionId, Arc<PendingTransaction<T>>>,
/// Transactions that can be executed right away: these have the expected nonce.
///
/// Once an `independent` transaction with the nonce `N` is returned, it unlocks `N+1`, which
/// then can be moved from the `all` set to the `independent` set.
pub(crate) independent: BTreeSet<PendingTransactionRef<T>>,
/// There might be the case where a yielded transactions is invalid, this will track it.
pub(crate) invalid: HashSet<TxHash>,
}
@ -35,6 +48,7 @@ impl<T: TransactionOrdering> Iterator for BestTransactions<T> {
fn next(&mut self) -> Option<Self::Item> {
loop {
// Remove the next independent tx with the highest priority
let best = self.independent.iter().next_back()?.clone();
let best = self.independent.take(&best)?;
let hash = best.transaction.hash();
@ -58,3 +72,62 @@ impl<T: TransactionOrdering> Iterator for BestTransactions<T> {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
pool::pending::PendingPool,
test_util::{MockOrdering, MockTransaction, MockTransactionFactory},
};
#[test]
fn test_best_iter() {
let mut pool = PendingPool::new(Arc::new(MockOrdering::default()));
let mut f = MockTransactionFactory::default();
let num_tx = 10;
// insert 10 gapless tx
let tx = MockTransaction::eip1559();
for nonce in 0..num_tx {
let tx = tx.clone().rng_hash().with_nonce(nonce);
let valid_tx = f.validated(tx);
pool.add_transaction(Arc::new(valid_tx));
}
let mut best = pool.best();
assert_eq!(best.all.len(), num_tx as usize);
assert_eq!(best.independent.len(), 1);
// check tx are returned in order
for nonce in 0..num_tx {
assert_eq!(best.independent.len(), 1);
let tx = best.next().unwrap();
assert_eq!(tx.nonce(), nonce);
}
}
#[test]
fn test_best_iter_invalid() {
let mut pool = PendingPool::new(Arc::new(MockOrdering::default()));
let mut f = MockTransactionFactory::default();
let num_tx = 10;
// insert 10 gapless tx
let tx = MockTransaction::eip1559();
for nonce in 0..num_tx {
let tx = tx.clone().rng_hash().with_nonce(nonce);
let valid_tx = f.validated(tx);
pool.add_transaction(Arc::new(valid_tx));
}
let mut best = pool.best();
// mark the first tx as invalid
let invalid = best.independent.iter().next().unwrap();
best.mark_invalid(&invalid.transaction.clone());
// iterator is empty
assert!(best.next().is_none());
}
}

View File

@ -9,8 +9,16 @@ use std::{
sync::Arc,
};
/// A pool of validated and gapless transactions that are ready on the current state and are waiting
/// to be included in a block.
/// A pool of validated and gapless transactions that are ready to be executed on the current state
/// and are waiting to be included in a block.
///
/// This pool distinguishes between `independent` transactions and pending transactions. A
/// transaction is `independent`, if it is in the pending pool, and it has the current on chain
/// nonce of the sender. Meaning `independent` transactions can be executed right away, other
/// pending transactions depend on at least one `independent` transaction.
///
/// Once an `independent` transaction was executed it *unlocks* the next nonce, if this transaction
/// is also pending, then this will be moved to the `independent` queue.
pub(crate) struct PendingPool<T: TransactionOrdering> {
/// How to order transactions.
ordering: Arc<T>,