reth_payload_util/
traits.rs1use std::sync::Arc;
2
3use alloy_primitives::{map::HashSet, Address};
4use reth_transaction_pool::{PoolTransaction, ValidPoolTransaction};
5
6pub trait PayloadTransactions {
12 type Transaction;
14
15 fn next(
17 &mut self,
18 ctx: (),
20 ) -> Option<Self::Transaction>;
21
22 fn mark_invalid(&mut self, sender: Address, nonce: u64);
25}
26
27#[derive(Debug, Clone, Copy)]
29pub struct NoopPayloadTransactions<T>(core::marker::PhantomData<T>);
30
31impl<T> Default for NoopPayloadTransactions<T> {
32 fn default() -> Self {
33 Self(Default::default())
34 }
35}
36
37impl<T> PayloadTransactions for NoopPayloadTransactions<T> {
38 type Transaction = T;
39
40 fn next(&mut self, _ctx: ()) -> Option<Self::Transaction> {
41 None
42 }
43
44 fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
45}
46
47#[derive(Debug)]
50pub struct BestPayloadTransactions<T, I>
51where
52 T: PoolTransaction,
53 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
54{
55 invalid: HashSet<Address>,
56 best: I,
57}
58
59impl<T, I> BestPayloadTransactions<T, I>
60where
61 T: PoolTransaction,
62 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
63{
64 pub fn new(best: I) -> Self {
66 Self { invalid: Default::default(), best }
67 }
68}
69
70impl<T, I> PayloadTransactions for BestPayloadTransactions<T, I>
71where
72 T: PoolTransaction,
73 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
74{
75 type Transaction = T;
76
77 fn next(&mut self, _ctx: ()) -> Option<Self::Transaction> {
78 loop {
79 let tx = self.best.next()?;
80 if self.invalid.contains(tx.sender_ref()) {
81 continue
82 }
83 return Some(tx.transaction.clone())
84 }
85 }
86
87 fn mark_invalid(&mut self, sender: Address, _nonce: u64) {
88 self.invalid.insert(sender);
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use std::sync::Arc;
95
96 use crate::{
97 BestPayloadTransactions, PayloadTransactions, PayloadTransactionsChain,
98 PayloadTransactionsFixed,
99 };
100 use alloy_primitives::{map::HashSet, Address};
101 use reth_transaction_pool::{
102 pool::{BestTransactionsWithPrioritizedSenders, PendingPool},
103 test_utils::{MockOrdering, MockTransaction, MockTransactionFactory},
104 PoolTransaction,
105 };
106
107 #[test]
108 fn test_best_transactions_chained_iterators() {
109 let mut priority_pool = PendingPool::new(MockOrdering::default());
110 let mut pool = PendingPool::new(MockOrdering::default());
111 let mut f = MockTransactionFactory::default();
112
113 let address_top_of_block = Address::random();
130 let address_in_priority_pool = Address::random();
131 let address_a = Address::random();
132 let address_b = Address::random();
133 let address_regular = Address::random();
134
135 {
137 let prioritized_tx_a =
138 MockTransaction::eip1559().with_gas_price(5).with_sender(address_a);
139 let prioritized_tx_b =
141 MockTransaction::eip1559().with_gas_price(10).with_sender(address_b);
142 let regular_tx =
143 MockTransaction::eip1559().with_gas_price(15).with_sender(address_regular);
144 pool.add_transaction(Arc::new(f.validated(prioritized_tx_a)), 0);
145 pool.add_transaction(Arc::new(f.validated(prioritized_tx_b)), 0);
146 pool.add_transaction(Arc::new(f.validated(regular_tx)), 0);
147 }
148
149 {
151 let prioritized_tx =
152 MockTransaction::eip1559().with_gas_price(0).with_sender(address_in_priority_pool);
153 let valid_prioritized_tx = f.validated(prioritized_tx);
154 priority_pool.add_transaction(Arc::new(valid_prioritized_tx), 0);
155 }
156
157 let mut block = PayloadTransactionsChain::new(
158 PayloadTransactionsFixed::single(
159 MockTransaction::eip1559().with_sender(address_top_of_block),
160 ),
161 Some(100),
162 PayloadTransactionsChain::new(
163 BestPayloadTransactions::new(priority_pool.best()),
164 Some(100),
165 BestPayloadTransactions::new(BestTransactionsWithPrioritizedSenders::new(
166 HashSet::from([address_a]),
167 200,
168 BestTransactionsWithPrioritizedSenders::new(
169 HashSet::from([address_b]),
170 200,
171 pool.best(),
172 ),
173 )),
174 None,
175 ),
176 None,
177 );
178
179 assert_eq!(block.next(()).unwrap().sender(), address_top_of_block);
180 assert_eq!(block.next(()).unwrap().sender(), address_in_priority_pool);
181 assert_eq!(block.next(()).unwrap().sender(), address_a);
182 assert_eq!(block.next(()).unwrap().sender(), address_b);
183 assert_eq!(block.next(()).unwrap().sender(), address_regular);
184 }
185}