mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
docs(txpool): update BestTransaction docs (#57)
This commit is contained in:
@ -10,10 +10,23 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::debug;
|
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> {
|
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>>>,
|
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>>,
|
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>,
|
pub(crate) invalid: HashSet<TxHash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +48,7 @@ impl<T: TransactionOrdering> Iterator for BestTransactions<T> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
loop {
|
loop {
|
||||||
|
// Remove the next independent tx with the highest priority
|
||||||
let best = self.independent.iter().next_back()?.clone();
|
let best = self.independent.iter().next_back()?.clone();
|
||||||
let best = self.independent.take(&best)?;
|
let best = self.independent.take(&best)?;
|
||||||
let hash = best.transaction.hash();
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -9,8 +9,16 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A pool of validated and gapless transactions that are ready on the current state and are waiting
|
/// A pool of validated and gapless transactions that are ready to be executed on the current state
|
||||||
/// to be included in a block.
|
/// 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> {
|
pub(crate) struct PendingPool<T: TransactionOrdering> {
|
||||||
/// How to order transactions.
|
/// How to order transactions.
|
||||||
ordering: Arc<T>,
|
ordering: Arc<T>,
|
||||||
|
|||||||
Reference in New Issue
Block a user