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);
28}
29
30#[derive(Debug, Clone, Copy)]
32pub struct NoopPayloadTransactions<T>(core::marker::PhantomData<T>);
33
34impl<T> Default for NoopPayloadTransactions<T> {
35 fn default() -> Self {
36 Self(Default::default())
37 }
38}
39
40impl<T> PayloadTransactions for NoopPayloadTransactions<T> {
41 type Transaction = T;
42
43 fn next(&mut self, _ctx: ()) -> Option<Self::Transaction> {
44 None
45 }
46
47 fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
48}
49
50#[derive(Debug)]
56pub struct BestPayloadTransactions<T, I>
57where
58 T: PoolTransaction,
59 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
60{
61 invalid: HashSet<Address>,
62 best: I,
63}
64
65impl<T, I> BestPayloadTransactions<T, I>
66where
67 T: PoolTransaction,
68 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
69{
70 pub fn new(best: I) -> Self {
72 Self { invalid: Default::default(), best }
73 }
74}
75
76impl<T, I> PayloadTransactions for BestPayloadTransactions<T, I>
77where
78 T: PoolTransaction,
79 I: Iterator<Item = Arc<ValidPoolTransaction<T>>>,
80{
81 type Transaction = T;
82
83 fn next(&mut self, _ctx: ()) -> Option<Self::Transaction> {
84 loop {
85 let tx = self.best.next()?;
86 if self.invalid.contains(tx.sender_ref()) {
87 continue
88 }
89 return Some(tx.transaction.clone())
90 }
91 }
92
93 fn mark_invalid(&mut self, sender: Address, _nonce: u64) {
94 self.invalid.insert(sender);
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use std::sync::Arc;
101
102 use crate::{
103 BestPayloadTransactions, PayloadTransactions, PayloadTransactionsChain,
104 PayloadTransactionsFixed,
105 };
106 use alloy_primitives::{map::HashSet, Address};
107 use reth_transaction_pool::{
108 pool::{BestTransactionsWithPrioritizedSenders, PendingPool},
109 test_utils::{MockOrdering, MockTransaction, MockTransactionFactory},
110 PoolTransaction,
111 };
112
113 #[test]
114 fn test_best_transactions_chained_iterators() {
115 let mut priority_pool = PendingPool::new(MockOrdering::default());
116 let mut pool = PendingPool::new(MockOrdering::default());
117 let mut f = MockTransactionFactory::default();
118
119 let address_top_of_block = Address::random();
136 let address_in_priority_pool = Address::random();
137 let address_a = Address::random();
138 let address_b = Address::random();
139 let address_regular = Address::random();
140
141 {
143 let prioritized_tx_a =
144 MockTransaction::eip1559().with_gas_price(5).with_sender(address_a);
145 let prioritized_tx_b =
147 MockTransaction::eip1559().with_gas_price(10).with_sender(address_b);
148 let regular_tx =
149 MockTransaction::eip1559().with_gas_price(15).with_sender(address_regular);
150 pool.add_transaction(Arc::new(f.validated(prioritized_tx_a)), 0);
151 pool.add_transaction(Arc::new(f.validated(prioritized_tx_b)), 0);
152 pool.add_transaction(Arc::new(f.validated(regular_tx)), 0);
153 }
154
155 {
157 let prioritized_tx =
158 MockTransaction::eip1559().with_gas_price(0).with_sender(address_in_priority_pool);
159 let valid_prioritized_tx = f.validated(prioritized_tx);
160 priority_pool.add_transaction(Arc::new(valid_prioritized_tx), 0);
161 }
162
163 let mut block = PayloadTransactionsChain::new(
164 PayloadTransactionsFixed::single(
165 MockTransaction::eip1559().with_sender(address_top_of_block),
166 ),
167 Some(100),
168 PayloadTransactionsChain::new(
169 BestPayloadTransactions::new(priority_pool.best()),
170 Some(100),
171 BestPayloadTransactions::new(BestTransactionsWithPrioritizedSenders::new(
172 HashSet::from([address_a]),
173 200,
174 BestTransactionsWithPrioritizedSenders::new(
175 HashSet::from([address_b]),
176 200,
177 pool.best(),
178 ),
179 )),
180 None,
181 ),
182 None,
183 );
184
185 assert_eq!(block.next(()).unwrap().sender(), address_top_of_block);
186 assert_eq!(block.next(()).unwrap().sender(), address_in_priority_pool);
187 assert_eq!(block.next(()).unwrap().sender(), address_a);
188 assert_eq!(block.next(()).unwrap().sender(), address_b);
189 assert_eq!(block.next(()).unwrap().sender(), address_regular);
190 }
191}