1use crate::transaction::TempoPooledTransaction;
4use reth_transaction_pool::{
5 BestTransactions, CoinbaseTipOrdering, Priority, TransactionOrdering,
6 error::InvalidPoolTransactionError,
7};
8
9pub trait BestPriorityTransactions<T: TransactionOrdering>: BestTransactions {
11 fn next_tx_and_priority(&mut self) -> Option<(Self::Item, Priority<T::PriorityValue>)>;
13}
14
15impl<T: TransactionOrdering> BestPriorityTransactions<T>
16 for reth_transaction_pool::pool::BestTransactions<T>
17{
18 fn next_tx_and_priority(&mut self) -> Option<(Self::Item, Priority<T::PriorityValue>)> {
19 Self::next_tx_and_priority(self)
20 }
21}
22impl BestPriorityTransactions<CoinbaseTipOrdering<TempoPooledTransaction>>
23 for crate::tt_2d_pool::BestAA2dTransactions
24{
25 fn next_tx_and_priority(&mut self) -> Option<(Self::Item, Priority<u128>)> {
26 Self::next_tx_and_priority(self)
27 }
28}
29
30pub struct MergeBestTransactions<L, R, T>
32where
33 L: BestPriorityTransactions<T>,
34 R: BestPriorityTransactions<T, Item = L::Item>,
35 T: TransactionOrdering,
36{
37 left: L,
38 right: R,
39 next_left: Option<(L::Item, Priority<T::PriorityValue>)>,
40 next_right: Option<(L::Item, Priority<T::PriorityValue>)>,
41}
42
43impl<L, R, T> MergeBestTransactions<L, R, T>
44where
45 L: BestPriorityTransactions<T>,
46 R: BestPriorityTransactions<T, Item = L::Item>,
47 T: TransactionOrdering,
48{
49 pub fn new(left: L, right: R) -> Self {
51 Self {
52 left,
53 right,
54 next_left: None,
55 next_right: None,
56 }
57 }
58}
59
60impl<L, R, T> MergeBestTransactions<L, R, T>
61where
62 L: BestPriorityTransactions<T>,
63 R: BestPriorityTransactions<T, Item = L::Item>,
64 T: TransactionOrdering,
65{
66 fn next_best(&mut self) -> Option<(L::Item, Priority<T::PriorityValue>)> {
68 if self.next_left.is_none() {
69 self.next_left = self.left.next_tx_and_priority();
70 }
71 if self.next_right.is_none() {
72 self.next_right = self.right.next_tx_and_priority();
73 }
74
75 match (&mut self.next_left, &mut self.next_right) {
76 (None, None) => {
77 None
79 }
80 (Some(_), None) => {
82 let (item, priority) = self.next_left.take()?;
83 Some((item, priority))
84 }
85 (None, Some(_)) => {
87 let (item, priority) = self.next_right.take()?;
88 Some((item, priority))
89 }
90 (Some((_, left_priority)), Some((_, right_priority))) => {
92 if left_priority >= right_priority {
94 let (item, priority) = self.next_left.take()?;
95 Some((item, priority))
96 } else {
97 let (item, priority) = self.next_right.take()?;
98 Some((item, priority))
99 }
100 }
101 }
102 }
103}
104
105impl<L, R, T> Iterator for MergeBestTransactions<L, R, T>
106where
107 L: BestPriorityTransactions<T>,
108 R: BestPriorityTransactions<T, Item = L::Item>,
109 T: TransactionOrdering,
110{
111 type Item = L::Item;
112
113 fn next(&mut self) -> Option<Self::Item> {
114 self.next_best().map(|(tx, _)| tx)
115 }
116}
117
118impl<L, R, T> BestTransactions for MergeBestTransactions<L, R, T>
119where
120 L: BestPriorityTransactions<T, Item: Send> + Send,
121 R: BestPriorityTransactions<T, Item = L::Item> + Send,
122 T: TransactionOrdering,
123{
124 fn mark_invalid(&mut self, transaction: &Self::Item, kind: &InvalidPoolTransactionError) {
125 self.left.mark_invalid(transaction, kind);
126 self.right.mark_invalid(transaction, kind);
127 }
128
129 fn no_updates(&mut self) {
130 self.left.no_updates();
131 self.right.no_updates();
132 }
133
134 fn set_skip_blobs(&mut self, skip_blobs: bool) {
135 self.left.set_skip_blobs(skip_blobs);
136 self.right.set_skip_blobs(skip_blobs);
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 struct MockBestTransactions<T> {
146 items: Vec<(T, Priority<u128>)>,
147 index: usize,
148 }
149
150 impl<T> MockBestTransactions<T> {
151 fn new(items: Vec<(T, u128)>) -> Self {
152 let items = items
153 .into_iter()
154 .map(|(item, priority)| (item, Priority::Value(priority)))
155 .collect();
156 Self { items, index: 0 }
157 }
158 }
159
160 impl<T: Clone> Iterator for MockBestTransactions<T> {
161 type Item = T;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 if self.index < self.items.len() {
165 let item = self.items[self.index].0.clone();
166 self.index += 1;
167 Some(item)
168 } else {
169 None
170 }
171 }
172 }
173
174 impl<T: Clone + Send>
175 BestPriorityTransactions<CoinbaseTipOrdering<crate::transaction::TempoPooledTransaction>>
176 for MockBestTransactions<T>
177 {
178 fn next_tx_and_priority(&mut self) -> Option<(Self::Item, Priority<u128>)> {
179 if self.index < self.items.len() {
180 let (item, priority) = &self.items[self.index];
181 let result = (item.clone(), priority.clone());
182 self.index += 1;
183 Some(result)
184 } else {
185 None
186 }
187 }
188 }
189
190 impl<T: Clone + Send> BestTransactions for MockBestTransactions<T> {
191 fn mark_invalid(&mut self, _transaction: &Self::Item, _kind: &InvalidPoolTransactionError) {
192 }
194
195 fn no_updates(&mut self) {
196 }
198
199 fn set_skip_blobs(&mut self, _skip_blobs: bool) {
200 }
202 }
203
204 #[test]
205 fn test_merge_best_transactions_basic() {
206 let left = MockBestTransactions::new(vec![("tx_a", 10), ("tx_b", 5), ("tx_c", 3)]);
211 let right = MockBestTransactions::new(vec![("tx_d", 8), ("tx_e", 4), ("tx_f", 1)]);
212
213 let mut merged = MergeBestTransactions::new(left, right);
214
215 assert_eq!(merged.next(), Some("tx_a")); assert_eq!(merged.next(), Some("tx_d")); assert_eq!(merged.next(), Some("tx_b")); assert_eq!(merged.next(), Some("tx_e")); assert_eq!(merged.next(), Some("tx_c")); assert_eq!(merged.next(), Some("tx_f")); assert_eq!(merged.next(), None);
222 }
223
224 #[test]
225 fn test_merge_best_transactions_empty_left() {
226 let left = MockBestTransactions::new(vec![]);
228 let right = MockBestTransactions::new(vec![("tx_a", 10), ("tx_b", 5)]);
229
230 let mut merged = MergeBestTransactions::new(left, right);
231
232 assert_eq!(merged.next(), Some("tx_a"));
233 assert_eq!(merged.next(), Some("tx_b"));
234 assert_eq!(merged.next(), None);
235 }
236
237 #[test]
238 fn test_merge_best_transactions_empty_right() {
239 let left = MockBestTransactions::new(vec![("tx_a", 10), ("tx_b", 5)]);
241 let right = MockBestTransactions::new(vec![]);
242
243 let mut merged = MergeBestTransactions::new(left, right);
244
245 assert_eq!(merged.next(), Some("tx_a"));
246 assert_eq!(merged.next(), Some("tx_b"));
247 assert_eq!(merged.next(), None);
248 }
249
250 #[test]
251 fn test_merge_best_transactions_both_empty() {
252 let left: MockBestTransactions<&str> = MockBestTransactions::new(vec![]);
253 let right: MockBestTransactions<&str> = MockBestTransactions::new(vec![]);
254
255 let mut merged = MergeBestTransactions::new(left, right);
256
257 assert_eq!(merged.next(), None);
258 }
259
260 #[test]
261 fn test_merge_best_transactions_equal_priorities() {
262 let left = MockBestTransactions::new(vec![("tx_a", 10), ("tx_b", 5)]);
264 let right = MockBestTransactions::new(vec![("tx_c", 10), ("tx_d", 5)]);
265
266 let mut merged = MergeBestTransactions::new(left, right);
267
268 assert_eq!(merged.next(), Some("tx_a")); assert_eq!(merged.next(), Some("tx_c"));
270 assert_eq!(merged.next(), Some("tx_b")); assert_eq!(merged.next(), Some("tx_d"));
272 assert_eq!(merged.next(), None);
273 }
274}