reth_transaction_pool/
ordering.rs

1use crate::traits::PoolTransaction;
2use std::{cmp::Ordering, fmt::Debug, marker::PhantomData};
3
4/// Priority of the transaction that can be missing.
5///
6/// Transactions with missing priorities are ranked lower.
7#[derive(PartialEq, Eq, Clone, Debug)]
8pub enum Priority<T: Ord + Clone> {
9    /// The value of the priority of the transaction.
10    Value(T),
11    /// Missing priority due to ordering internals.
12    None,
13}
14
15impl<T: Ord + Clone> From<Option<T>> for Priority<T> {
16    fn from(value: Option<T>) -> Self {
17        value.map_or(Self::None, Priority::Value)
18    }
19}
20
21impl<T: Ord + Clone> PartialOrd for Priority<T> {
22    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
23        Some(self.cmp(other))
24    }
25}
26
27impl<T: Ord + Clone> Ord for Priority<T> {
28    fn cmp(&self, other: &Self) -> Ordering {
29        match (self, other) {
30            (Self::Value(a), Self::Value(b)) => a.cmp(b),
31            // Note: None should be smaller than Value.
32            (Self::Value(_), Self::None) => Ordering::Greater,
33            (Self::None, Self::Value(_)) => Ordering::Less,
34            (Self::None, Self::None) => Ordering::Equal,
35        }
36    }
37}
38
39/// Transaction ordering trait to determine the order of transactions.
40///
41/// Decides how transactions should be ordered within the pool, depending on a `Priority` value.
42///
43/// The returned priority must reflect [total order](https://en.wikipedia.org/wiki/Total_order).
44pub trait TransactionOrdering: Debug + Send + Sync + 'static {
45    /// Priority of a transaction.
46    ///
47    /// Higher is better.
48    type PriorityValue: Ord + Clone + Default + Debug + Send + Sync;
49
50    /// The transaction type to determine the priority of.
51    type Transaction: PoolTransaction;
52
53    /// Returns the priority score for the given transaction.
54    fn priority(
55        &self,
56        transaction: &Self::Transaction,
57        base_fee: u64,
58    ) -> Priority<Self::PriorityValue>;
59}
60
61/// Default ordering for the pool.
62///
63/// The transactions are ordered by their coinbase tip.
64/// The higher the coinbase tip is, the higher the priority of the transaction.
65#[derive(Debug)]
66#[non_exhaustive]
67pub struct CoinbaseTipOrdering<T>(PhantomData<T>);
68
69impl<T> TransactionOrdering for CoinbaseTipOrdering<T>
70where
71    T: PoolTransaction + 'static,
72{
73    type PriorityValue = u128;
74    type Transaction = T;
75
76    /// Source: <https://github.com/ethereum/go-ethereum/blob/7f756dc1185d7f1eeeacb1d12341606b7135f9ea/core/txpool/legacypool/list.go#L469-L482>.
77    ///
78    /// NOTE: The implementation is incomplete for missing base fee.
79    fn priority(
80        &self,
81        transaction: &Self::Transaction,
82        base_fee: u64,
83    ) -> Priority<Self::PriorityValue> {
84        transaction.effective_tip_per_gas(base_fee).into()
85    }
86}
87
88impl<T> Default for CoinbaseTipOrdering<T> {
89    fn default() -> Self {
90        Self(Default::default())
91    }
92}
93
94impl<T> Clone for CoinbaseTipOrdering<T> {
95    fn clone(&self) -> Self {
96        Self::default()
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_priority_ordering() {
106        let p1 = Priority::Value(3);
107        let p2 = Priority::Value(1);
108        let p3 = Priority::None;
109
110        assert!(p1 > p2); // 3 > 1
111        assert!(p1 > p3); // Value(3) > None
112        assert!(p2 > p3); // Value(1) > None
113        assert_eq!(p3, Priority::None);
114    }
115}