use crate::traits::PoolTransaction; use alloy_primitives::U256; use std::{cmp::Ordering, fmt::Debug, marker::PhantomData}; /// Priority of the transaction that can be missing. /// /// Transactions with missing priorities are ranked lower. #[derive(PartialEq, Eq, Clone, Debug)] pub enum Priority { /// The value of the priority of the transaction. Value(T), /// Missing priority due to ordering internals. None, } impl From> for Priority { fn from(value: Option) -> Self { value.map_or(Self::None, Priority::Value) } } impl PartialOrd for Priority { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Priority { fn cmp(&self, other: &Self) -> Ordering { match (self, other) { (Self::Value(a), Self::Value(b)) => a.cmp(b), // Note: None should be smaller than Value. (Self::Value(_), Self::None) => Ordering::Greater, (Self::None, Self::Value(_)) => Ordering::Less, (Self::None, Self::None) => Ordering::Equal, } } } /// Transaction ordering trait to determine the order of transactions. /// /// Decides how transactions should be ordered within the pool, depending on a `Priority` value. /// /// The returned priority must reflect [total order](https://en.wikipedia.org/wiki/Total_order). pub trait TransactionOrdering: Debug + Send + Sync + 'static { /// Priority of a transaction. /// /// Higher is better. type PriorityValue: Ord + Clone + Default + Debug + Send + Sync; /// The transaction type to determine the priority of. type Transaction: PoolTransaction; /// Returns the priority score for the given transaction. fn priority( &self, transaction: &Self::Transaction, base_fee: u64, ) -> Priority; } /// Default ordering for the pool. /// /// The transactions are ordered by their coinbase tip. /// The higher the coinbase tip is, the higher the priority of the transaction. #[derive(Debug)] #[non_exhaustive] pub struct CoinbaseTipOrdering(PhantomData); impl TransactionOrdering for CoinbaseTipOrdering where T: PoolTransaction + 'static, { type PriorityValue = U256; type Transaction = T; /// Source: . /// /// NOTE: The implementation is incomplete for missing base fee. fn priority( &self, transaction: &Self::Transaction, base_fee: u64, ) -> Priority { transaction.effective_tip_per_gas(base_fee).map(U256::from).into() } } impl Default for CoinbaseTipOrdering { fn default() -> Self { Self(Default::default()) } } impl Clone for CoinbaseTipOrdering { fn clone(&self) -> Self { Self::default() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_priority_ordering() { let p1 = Priority::Value(3); let p2 = Priority::Value(1); let p3 = Priority::None; assert!(p1 > p2); // 3 > 1 assert!(p1 > p3); // Value(3) > None assert!(p2 > p3); // Value(1) > None assert_eq!(p3, Priority::None); } }