1use crate::{
2 identifier::{SenderId, TransactionId},
3 pool::size::SizeTracker,
4 PoolTransaction, SubPoolLimit, ValidPoolTransaction, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
5};
6use rustc_hash::FxHashMap;
7use smallvec::SmallVec;
8use std::{
9 cmp::Ordering,
10 collections::{hash_map::Entry, BTreeMap, BTreeSet},
11 ops::{Bound::Unbounded, Deref},
12 sync::Arc,
13};
14
15#[derive(Debug, Clone)]
22pub struct ParkedPool<T: ParkedOrd> {
23 submission_id: u64,
27 by_id: BTreeMap<TransactionId, ParkedPoolTransaction<T>>,
29 last_sender_submission: BTreeSet<SubmissionSenderId>,
34 sender_transaction_count: FxHashMap<SenderId, SenderTransactionCount>,
37 size_of: SizeTracker,
41}
42
43impl<T: ParkedOrd> ParkedPool<T> {
46 pub fn add_transaction(&mut self, tx: Arc<ValidPoolTransaction<T::Transaction>>) {
48 let id = *tx.id();
49 debug_assert!(
50 !self.contains(&id),
51 "transaction already included {:?}",
52 self.get(&id).unwrap().transaction.transaction
53 );
54 let submission_id = self.next_id();
55
56 self.size_of += tx.size();
58
59 self.add_sender_count(tx.sender_id(), submission_id);
61 let transaction = ParkedPoolTransaction { submission_id, transaction: tx.into() };
62
63 self.by_id.insert(id, transaction);
64 }
65
66 fn add_sender_count(&mut self, sender: SenderId, submission_id: u64) {
69 match self.sender_transaction_count.entry(sender) {
70 Entry::Occupied(mut entry) => {
71 let value = entry.get_mut();
72 self.last_sender_submission
74 .remove(&SubmissionSenderId::new(sender, value.last_submission_id));
75
76 value.count += 1;
77 value.last_submission_id = submission_id;
78 }
79 Entry::Vacant(entry) => {
80 entry
81 .insert(SenderTransactionCount { count: 1, last_submission_id: submission_id });
82 }
83 }
84 self.last_sender_submission.insert(SubmissionSenderId::new(sender, submission_id));
86 }
87
88 fn remove_sender_count(&mut self, sender_id: SenderId) {
95 let removed_sender = match self.sender_transaction_count.entry(sender_id) {
96 Entry::Occupied(mut entry) => {
97 let value = entry.get_mut();
98 value.count -= 1;
99 if value.count == 0 {
100 entry.remove()
101 } else {
102 return
103 }
104 }
105 Entry::Vacant(_) => {
106 unreachable!("sender count not found {:?}", sender_id);
108 }
109 };
110
111 assert!(
113 self.last_sender_submission
114 .remove(&SubmissionSenderId::new(sender_id, removed_sender.last_submission_id)),
115 "last sender transaction not found {sender_id:?}"
116 );
117 }
118
119 pub(crate) fn all(
121 &self,
122 ) -> impl ExactSizeIterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
123 self.by_id.values().map(|tx| tx.transaction.clone().into())
124 }
125
126 pub(crate) fn remove_transaction(
128 &mut self,
129 id: &TransactionId,
130 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
131 let tx = self.by_id.remove(id)?;
133 self.remove_sender_count(tx.transaction.sender_id());
134
135 self.size_of -= tx.transaction.size();
137
138 Some(tx.transaction.into())
139 }
140
141 pub(crate) fn get_txs_by_sender(
144 &self,
145 sender: SenderId,
146 ) -> SmallVec<[TransactionId; TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER]> {
147 self.by_id
148 .range((sender.start_bound(), Unbounded))
149 .take_while(move |(other, _)| sender == other.sender)
150 .map(|(tx_id, _)| *tx_id)
151 .collect()
152 }
153
154 pub(crate) fn txs_by_sender(
157 &self,
158 sender: SenderId,
159 ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
160 self.by_id
161 .range((sender.start_bound(), Unbounded))
162 .take_while(move |(other, _)| sender == other.sender)
163 .map(|(_, tx)| Arc::clone(&tx.transaction))
164 }
165
166 #[cfg(test)]
167 pub(crate) fn get_senders_by_submission_id(
168 &self,
169 ) -> impl Iterator<Item = SubmissionSenderId> + '_ {
170 self.last_sender_submission.iter().copied()
171 }
172
173 pub fn truncate_pool(
187 &mut self,
188 limit: SubPoolLimit,
189 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
190 if !self.exceeds(&limit) {
191 return Vec::new()
193 }
194
195 let mut removed = Vec::with_capacity(limit.tx_excess(self.len()).unwrap_or(1));
196
197 while !self.last_sender_submission.is_empty() && limit.is_exceeded(self.len(), self.size())
198 {
199 let sender_id = self.last_sender_submission.last().unwrap().sender_id;
201
202 while let Some((tx_id, _)) = self.by_id.range(sender_id.range()).next_back() {
204 let tx_id = *tx_id;
205 if let Some(tx) = self.remove_transaction(&tx_id) {
206 removed.push(tx);
207 }
208
209 if !self.exceeds(&limit) {
210 break
211 }
212 }
213 }
214
215 removed
216 }
217
218 const fn next_id(&mut self) -> u64 {
219 let id = self.submission_id;
220 self.submission_id = self.submission_id.wrapping_add(1);
221 id
222 }
223
224 pub(crate) fn size(&self) -> usize {
226 self.size_of.into()
227 }
228
229 pub(crate) fn len(&self) -> usize {
231 self.by_id.len()
232 }
233
234 #[inline]
236 pub(crate) fn exceeds(&self, limit: &SubPoolLimit) -> bool {
237 limit.is_exceeded(self.len(), self.size())
238 }
239
240 #[cfg(test)]
242 pub(crate) fn is_empty(&self) -> bool {
243 self.by_id.is_empty()
244 }
245
246 pub(crate) fn contains(&self, id: &TransactionId) -> bool {
248 self.by_id.contains_key(id)
249 }
250
251 fn get(&self, id: &TransactionId) -> Option<&ParkedPoolTransaction<T>> {
253 self.by_id.get(id)
254 }
255
256 #[cfg(any(test, feature = "test-utils"))]
258 pub(crate) fn assert_invariants(&self) {
259 assert_eq!(
260 self.last_sender_submission.len(),
261 self.sender_transaction_count.len(),
262 "last_sender_submission.len() != sender_transaction_count.len()"
263 );
264 }
265}
266
267impl<T: PoolTransaction> ParkedPool<BasefeeOrd<T>> {
268 pub(crate) fn satisfy_base_fee_transactions(
272 &self,
273 basefee: u64,
274 ) -> Vec<Arc<ValidPoolTransaction<T>>> {
275 let mut txs = Vec::new();
276 self.satisfy_base_fee_ids(basefee as u128, |tx| {
277 txs.push(tx.clone());
278 });
279 txs
280 }
281
282 fn satisfy_base_fee_ids<F>(&self, basefee: u128, mut tx_handler: F)
284 where
285 F: FnMut(&Arc<ValidPoolTransaction<T>>),
286 {
287 let mut iter = self.by_id.iter().peekable();
288
289 while let Some((id, tx)) = iter.next() {
290 if tx.transaction.max_fee_per_gas() < basefee {
291 'this: while let Some((peek, _)) = iter.peek() {
293 if peek.sender != id.sender {
294 break 'this
295 }
296 iter.next();
297 }
298 } else {
299 tx_handler(&tx.transaction);
300 }
301 }
302 }
303
304 pub(crate) fn enforce_basefee_with<F>(&mut self, basefee: u64, mut tx_handler: F)
316 where
317 F: FnMut(Arc<ValidPoolTransaction<T>>),
318 {
319 let mut to_remove = Vec::new();
320 self.satisfy_base_fee_ids(basefee as u128, |tx| {
321 to_remove.push(*tx.id());
322 });
323
324 for id in to_remove {
325 if let Some(tx) = self.remove_transaction(&id) {
326 tx_handler(tx);
327 }
328 }
329 }
330
331 #[cfg(test)]
339 pub(crate) fn enforce_basefee(&mut self, basefee: u64) -> Vec<Arc<ValidPoolTransaction<T>>> {
340 let mut removed = Vec::new();
341 self.enforce_basefee_with(basefee, |tx| {
342 removed.push(tx);
343 });
344 removed
345 }
346}
347
348impl<T: ParkedOrd> Default for ParkedPool<T> {
349 fn default() -> Self {
350 Self {
351 submission_id: 0,
352 by_id: Default::default(),
353 last_sender_submission: Default::default(),
354 sender_transaction_count: Default::default(),
355 size_of: Default::default(),
356 }
357 }
358}
359
360#[derive(Debug, Clone, Default, PartialEq, Eq)]
362struct SenderTransactionCount {
363 count: u64,
364 last_submission_id: u64,
365}
366
367#[derive(Debug)]
369struct ParkedPoolTransaction<T: ParkedOrd> {
370 submission_id: u64,
372 transaction: T,
374}
375
376impl<T: ParkedOrd> Clone for ParkedPoolTransaction<T> {
377 fn clone(&self) -> Self {
378 Self { submission_id: self.submission_id, transaction: self.transaction.clone() }
379 }
380}
381
382impl<T: ParkedOrd> Eq for ParkedPoolTransaction<T> {}
383
384impl<T: ParkedOrd> PartialEq<Self> for ParkedPoolTransaction<T> {
385 fn eq(&self, other: &Self) -> bool {
386 self.cmp(other) == Ordering::Equal
387 }
388}
389
390impl<T: ParkedOrd> PartialOrd<Self> for ParkedPoolTransaction<T> {
391 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
392 Some(self.cmp(other))
393 }
394}
395
396impl<T: ParkedOrd> Ord for ParkedPoolTransaction<T> {
397 fn cmp(&self, other: &Self) -> Ordering {
398 self.transaction
402 .cmp(&other.transaction)
403 .then_with(|| other.submission_id.cmp(&self.submission_id))
404 }
405}
406
407#[derive(Debug, PartialEq, Eq, Copy, Clone)]
410pub(crate) struct SubmissionSenderId {
411 pub(crate) sender_id: SenderId,
413 pub(crate) submission_id: u64,
415}
416
417impl SubmissionSenderId {
418 const fn new(sender_id: SenderId, submission_id: u64) -> Self {
420 Self { sender_id, submission_id }
421 }
422}
423
424impl Ord for SubmissionSenderId {
425 fn cmp(&self, other: &Self) -> Ordering {
426 other.submission_id.cmp(&self.submission_id)
428 }
429}
430
431impl PartialOrd for SubmissionSenderId {
432 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
433 Some(self.cmp(other))
434 }
435}
436
437pub trait ParkedOrd:
441 Ord
442 + Clone
443 + From<Arc<ValidPoolTransaction<Self::Transaction>>>
444 + Into<Arc<ValidPoolTransaction<Self::Transaction>>>
445 + Deref<Target = Arc<ValidPoolTransaction<Self::Transaction>>>
446{
447 type Transaction: PoolTransaction;
449}
450
451macro_rules! impl_ord_wrapper {
453 ($name:ident) => {
454 impl<T: PoolTransaction> Clone for $name<T> {
455 fn clone(&self) -> Self {
456 Self(self.0.clone())
457 }
458 }
459
460 impl<T: PoolTransaction> Eq for $name<T> {}
461
462 impl<T: PoolTransaction> PartialEq<Self> for $name<T> {
463 fn eq(&self, other: &Self) -> bool {
464 self.cmp(other) == Ordering::Equal
465 }
466 }
467
468 impl<T: PoolTransaction> PartialOrd<Self> for $name<T> {
469 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
470 Some(self.cmp(other))
471 }
472 }
473 impl<T: PoolTransaction> Deref for $name<T> {
474 type Target = Arc<ValidPoolTransaction<T>>;
475
476 fn deref(&self) -> &Self::Target {
477 &self.0
478 }
479 }
480
481 impl<T: PoolTransaction> ParkedOrd for $name<T> {
482 type Transaction = T;
483 }
484
485 impl<T: PoolTransaction> From<Arc<ValidPoolTransaction<T>>> for $name<T> {
486 fn from(value: Arc<ValidPoolTransaction<T>>) -> Self {
487 Self(value)
488 }
489 }
490
491 impl<T: PoolTransaction> From<$name<T>> for Arc<ValidPoolTransaction<T>> {
492 fn from(value: $name<T>) -> Arc<ValidPoolTransaction<T>> {
493 value.0
494 }
495 }
496 };
497}
498
499#[derive(Debug)]
505pub struct BasefeeOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>);
506
507impl_ord_wrapper!(BasefeeOrd);
508
509impl<T: PoolTransaction> Ord for BasefeeOrd<T> {
510 fn cmp(&self, other: &Self) -> Ordering {
511 self.0.transaction.max_fee_per_gas().cmp(&other.0.transaction.max_fee_per_gas())
512 }
513}
514
515#[derive(Debug)]
525pub struct QueuedOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>);
526
527impl_ord_wrapper!(QueuedOrd);
528
529impl<T: PoolTransaction> Ord for QueuedOrd<T> {
530 fn cmp(&self, other: &Self) -> Ordering {
531 self.max_fee_per_gas().cmp(&other.max_fee_per_gas()).then_with(||
533 other.timestamp.cmp(&self.timestamp))
535 }
536}
537
538#[cfg(test)]
539mod tests {
540
541 use super::*;
542 use crate::test_utils::{MockTransaction, MockTransactionFactory, MockTransactionSet};
543 use alloy_consensus::{Transaction, TxType};
544 use alloy_primitives::Address;
545 use std::collections::HashSet;
546
547 #[test]
548 fn test_enforce_parked_basefee() {
549 let mut f = MockTransactionFactory::default();
550 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
551 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
552 pool.add_transaction(tx.clone());
553
554 assert!(pool.contains(tx.id()));
555 assert_eq!(pool.len(), 1);
556
557 let removed = pool.enforce_basefee(u64::MAX);
558 assert!(removed.is_empty());
559
560 let removed = pool.enforce_basefee((tx.max_fee_per_gas() - 1) as u64);
561 assert_eq!(removed.len(), 1);
562 assert!(pool.is_empty());
563 }
564
565 #[test]
566 fn test_enforce_parked_basefee_descendant() {
567 let mut f = MockTransactionFactory::default();
568 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
569 let t = MockTransaction::eip1559().inc_price_by(10);
570 let root_tx = f.validated_arc(t.clone());
571 pool.add_transaction(root_tx.clone());
572
573 let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
574 pool.add_transaction(descendant_tx.clone());
575
576 assert!(pool.contains(root_tx.id()));
577 assert!(pool.contains(descendant_tx.id()));
578 assert_eq!(pool.len(), 2);
579
580 let removed = pool.enforce_basefee(u64::MAX);
581 assert!(removed.is_empty());
582 assert_eq!(pool.len(), 2);
583 let removed = pool.enforce_basefee(descendant_tx.max_fee_per_gas() as u64);
587 assert_eq!(removed.len(), 2);
588 assert!(pool.is_empty());
589 }
590
591 #[test]
592 fn test_enforce_parked_basefee_removes_only_eligible_ancestor() {
593 let mut f = MockTransactionFactory::default();
594 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
595 let t = MockTransaction::eip1559().inc_price_by(10);
596
597 let root_tx = f.validated_arc(t.clone());
598 pool.add_transaction(root_tx.clone());
599
600 let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
601 pool.add_transaction(descendant_tx.clone());
602
603 let removed = pool.enforce_basefee(root_tx.max_fee_per_gas() as u64);
604
605 assert_eq!(removed.len(), 1);
606 assert_eq!(removed[0].id(), root_tx.id());
607 assert_eq!(pool.len(), 1);
608 assert!(!pool.contains(root_tx.id()));
609 assert!(pool.contains(descendant_tx.id()));
610 }
611
612 #[test]
613 fn truncate_parked_by_submission_id() {
614 let mut f = MockTransactionFactory::default();
616 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
617
618 let a_sender = Address::with_last_byte(0x0a);
619 let b_sender = Address::with_last_byte(0x0b);
620 let c_sender = Address::with_last_byte(0x0c);
621 let d_sender = Address::with_last_byte(0x0d);
622
623 let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
625 let a = tx_set.clone().into_vec();
626
627 let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
628 tx_set.extend(b.clone());
629
630 let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
632 tx_set.extend(c.clone());
633
634 let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
635 tx_set.extend(d.clone());
636
637 let all_txs = tx_set.into_vec();
638
639 let expected_parked = vec![c[0].clone(), c[1].clone(), c[2].clone(), d[0].clone()]
641 .into_iter()
642 .map(|tx| (tx.sender(), tx.nonce()))
643 .collect::<HashSet<_>>();
644
645 let expected_removed = vec![
649 a[0].clone(),
650 a[1].clone(),
651 a[2].clone(),
652 a[3].clone(),
653 b[0].clone(),
654 b[1].clone(),
655 b[2].clone(),
656 ]
657 .into_iter()
658 .map(|tx| (tx.sender(), tx.nonce()))
659 .collect::<HashSet<_>>();
660
661 for tx in all_txs {
663 pool.add_transaction(f.validated_arc(tx));
664 }
665
666 let pool_limit = SubPoolLimit { max_txs: 4, max_size: usize::MAX };
668
669 let removed = pool.truncate_pool(pool_limit);
671 assert_eq!(removed.len(), expected_removed.len());
672
673 let removed =
675 removed.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
676 assert_eq!(removed, expected_removed);
677
678 let parked = pool.all().collect::<Vec<_>>();
680 assert_eq!(parked.len(), expected_parked.len());
681
682 let parked = parked.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
684 assert_eq!(parked, expected_parked);
685 }
686
687 #[test]
688 fn test_truncate_parked_with_large_tx() {
689 let mut f = MockTransactionFactory::default();
690 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
691 let default_limits = SubPoolLimit::default();
692
693 let a_sender = Address::with_last_byte(0x0a);
696
697 let a_txs = MockTransactionSet::dependent(a_sender, 0, 2, TxType::Eip1559)
699 .into_iter()
700 .map(|mut tx| {
701 tx.set_size(default_limits.max_size / 2 + 1);
702 tx
703 })
704 .collect::<Vec<_>>();
705
706 for tx in a_txs {
708 pool.add_transaction(f.validated_arc(tx));
709 }
710
711 let removed = pool.truncate_pool(default_limits);
713 assert_eq!(removed.len(), 1);
714 }
715
716 #[test]
717 fn test_senders_by_submission_id() {
718 let mut f = MockTransactionFactory::default();
720 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
721
722 let a_sender = Address::with_last_byte(0x0a);
723 let b_sender = Address::with_last_byte(0x0b);
724 let c_sender = Address::with_last_byte(0x0c);
725 let d_sender = Address::with_last_byte(0x0d);
726
727 let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
729 let a = tx_set.clone().into_vec();
730
731 let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
732 tx_set.extend(b.clone());
733
734 let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
736 tx_set.extend(c.clone());
737
738 let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
739 tx_set.extend(d.clone());
740
741 let all_txs = tx_set.into_vec();
742
743 for tx in all_txs {
745 pool.add_transaction(f.validated_arc(tx));
746 }
747
748 let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
750 assert_eq!(senders.len(), 4);
751 let expected_senders = vec![d_sender, c_sender, b_sender, a_sender]
752 .into_iter()
753 .map(|s| f.ids.sender_id(&s).unwrap())
754 .collect::<Vec<_>>();
755 assert_eq!(senders, expected_senders);
756
757 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
759 let all_txs = vec![d[0].clone(), b[0].clone(), c[0].clone(), a[0].clone()];
760
761 for tx in all_txs {
763 pool.add_transaction(f.validated_arc(tx));
764 }
765
766 let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
767 assert_eq!(senders.len(), 4);
768 let expected_senders = vec![a_sender, c_sender, b_sender, d_sender]
769 .into_iter()
770 .map(|s| f.ids.sender_id(&s).unwrap())
771 .collect::<Vec<_>>();
772 assert_eq!(senders, expected_senders);
773 }
774
775 #[test]
776 fn test_add_sender_count_new_sender() {
777 let mut f = MockTransactionFactory::default();
779 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
781 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
783 pool.add_transaction(tx);
784
785 let sender: SenderId = 11.into();
787 let submission_id = 1;
788
789 pool.add_sender_count(sender, submission_id);
791
792 assert_eq!(pool.sender_transaction_count.len(), 2);
794 let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
795 assert_eq!(sender_info.count, 1);
796 assert_eq!(sender_info.last_submission_id, submission_id);
797
798 assert_eq!(pool.last_sender_submission.len(), 2);
800 let submission_info = pool.last_sender_submission.iter().next().unwrap();
801 assert_eq!(submission_info.sender_id, sender);
802 assert_eq!(submission_info.submission_id, submission_id);
803 }
804
805 #[test]
806 fn test_add_sender_count_existing_sender() {
807 let mut f = MockTransactionFactory::default();
809 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
811 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
813 pool.add_transaction(tx);
814
815 let sender: SenderId = 11.into();
817 let initial_submission_id = 1;
818
819 pool.add_sender_count(sender, initial_submission_id);
821
822 let new_submission_id = 2;
824 pool.add_sender_count(sender, new_submission_id);
826
827 assert_eq!(pool.sender_transaction_count.len(), 2);
829 let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
830 assert_eq!(sender_info.count, 2);
831 assert_eq!(sender_info.last_submission_id, new_submission_id);
832
833 assert_eq!(pool.last_sender_submission.len(), 2);
835 let submission_info = pool.last_sender_submission.iter().next().unwrap();
836 assert_eq!(submission_info.sender_id, sender);
837 assert_eq!(submission_info.submission_id, new_submission_id);
838 }
839
840 #[test]
841 fn test_add_sender_count_multiple_senders() {
842 let mut f = MockTransactionFactory::default();
844 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
846 let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
848 let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
849 pool.add_transaction(tx1);
850 pool.add_transaction(tx2);
851
852 let sender1: SenderId = 11.into();
854 let sender2: SenderId = 22.into();
855
856 pool.add_sender_count(sender1, 1);
858 pool.add_sender_count(sender2, 2);
859
860 assert_eq!(pool.sender_transaction_count.len(), 4);
862
863 let sender1_info = pool.sender_transaction_count.get(&sender1).unwrap();
864 assert_eq!(sender1_info.count, 1);
865 assert_eq!(sender1_info.last_submission_id, 1);
866
867 let sender2_info = pool.sender_transaction_count.get(&sender2).unwrap();
868 assert_eq!(sender2_info.count, 1);
869 assert_eq!(sender2_info.last_submission_id, 2);
870
871 assert_eq!(pool.last_sender_submission.len(), 3);
873
874 let submission_info1 =
876 pool.last_sender_submission.iter().find(|info| info.sender_id == sender1);
877 assert!(submission_info1.is_none());
878
879 let submission_info2 =
881 pool.last_sender_submission.iter().find(|info| info.sender_id == sender2).unwrap();
882 assert_eq!(submission_info2.sender_id, sender2);
883 assert_eq!(submission_info2.submission_id, 2);
884 }
885
886 #[test]
887 fn test_remove_sender_count() {
888 let mut f = MockTransactionFactory::default();
890 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
892 let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
894 let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
895 pool.add_transaction(tx1);
896 pool.add_transaction(tx2);
897
898 let sender1: SenderId = 11.into();
900 let sender2: SenderId = 22.into();
901
902 pool.add_sender_count(sender1, 1);
904
905 pool.add_sender_count(sender2, 2);
907 pool.add_sender_count(sender2, 3);
908
909 assert_eq!(pool.sender_transaction_count.len(), 4);
911 assert!(pool.sender_transaction_count.contains_key(&sender1));
912
913 assert_eq!(pool.sender_transaction_count.get(&sender1).unwrap().count, 1);
915
916 pool.remove_sender_count(sender1);
918
919 assert_eq!(pool.sender_transaction_count.len(), 3);
921 assert!(!pool.sender_transaction_count.contains_key(&sender1));
922
923 assert_eq!(
925 *pool.sender_transaction_count.get(&sender2).unwrap(),
926 SenderTransactionCount { count: 2, last_submission_id: 3 }
927 );
928
929 pool.remove_sender_count(sender2);
931
932 assert_eq!(pool.sender_transaction_count.len(), 3);
937 assert!(pool.sender_transaction_count.contains_key(&sender2));
938
939 assert_eq!(
941 *pool.sender_transaction_count.get(&sender2).unwrap(),
942 SenderTransactionCount { count: 1, last_submission_id: 3 }
943 );
944 }
945
946 #[test]
947 fn test_pool_size() {
948 let mut f = MockTransactionFactory::default();
949 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
950
951 let tx = f.validated_arc(MockTransaction::eip1559().set_size(1024).clone());
953 pool.add_transaction(tx);
954
955 assert_eq!(pool.size(), 1024);
957 }
958
959 #[test]
960 fn test_pool_len() {
961 let mut f = MockTransactionFactory::default();
962 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
963
964 assert_eq!(pool.len(), 0);
966
967 let tx = f.validated_arc(MockTransaction::eip1559());
969 pool.add_transaction(tx);
970 assert_eq!(pool.len(), 1);
971 }
972
973 #[test]
974 fn test_pool_contains() {
975 let mut f = MockTransactionFactory::default();
976 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
977
978 let tx = f.validated_arc(MockTransaction::eip1559());
980 let tx_id = *tx.id();
981
982 assert!(!pool.contains(&tx_id));
984
985 pool.add_transaction(tx);
987 assert!(pool.contains(&tx_id));
988 }
989
990 #[test]
991 fn test_get_transaction() {
992 let mut f = MockTransactionFactory::default();
993 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
994
995 let tx = f.validated_arc(MockTransaction::eip1559());
997 let tx_id = *tx.id();
998 pool.add_transaction(tx.clone());
999
1000 let retrieved = pool.get(&tx_id).expect("Transaction should exist in the pool");
1002 assert_eq!(retrieved.transaction.id(), tx.id());
1003 }
1004
1005 #[test]
1006 fn test_all_transactions() {
1007 let mut f = MockTransactionFactory::default();
1008 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1009
1010 let tx1 = f.validated_arc(MockTransaction::eip1559());
1012 let tx2 = f.validated_arc(MockTransaction::eip1559());
1013 pool.add_transaction(tx1.clone());
1014 pool.add_transaction(tx2.clone());
1015
1016 let all_txs: Vec<_> = pool.all().map(|tx| *tx.id()).collect();
1018 assert_eq!(all_txs.len(), 2);
1019
1020 assert!(all_txs.contains(tx1.id()));
1022 assert!(all_txs.contains(tx2.id()));
1023 }
1024
1025 #[test]
1026 fn test_truncate_pool_edge_case() {
1027 let mut f = MockTransactionFactory::default();
1028 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1029
1030 let tx1 = f.validated_arc(MockTransaction::eip1559());
1032 let tx2 = f.validated_arc(MockTransaction::eip1559());
1033 pool.add_transaction(tx1);
1034 pool.add_transaction(tx2);
1035
1036 let limit = SubPoolLimit { max_txs: 2, max_size: usize::MAX };
1038 let removed = pool.truncate_pool(limit);
1039
1040 assert!(removed.is_empty());
1042
1043 let limit = SubPoolLimit { max_txs: 1, max_size: usize::MAX };
1045 let removed = pool.truncate_pool(limit);
1046
1047 assert_eq!(removed.len(), 1);
1049 assert_eq!(pool.len(), 1);
1050 }
1051
1052 #[test]
1053 fn test_satisfy_base_fee_transactions() {
1054 let mut f = MockTransactionFactory::default();
1055 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1056
1057 let tx1 = f.validated_arc(MockTransaction::eip1559().set_max_fee(100).clone());
1059 let tx2 = f.validated_arc(MockTransaction::eip1559().set_max_fee(200).clone());
1060 pool.add_transaction(tx1);
1061 pool.add_transaction(tx2.clone());
1062
1063 let satisfied = pool.satisfy_base_fee_transactions(150);
1065 assert_eq!(satisfied.len(), 1);
1066 assert_eq!(satisfied[0].id(), tx2.id())
1067 }
1068
1069 #[test]
1070 fn test_remove_transaction() {
1071 let mut f = MockTransactionFactory::default();
1072 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1073
1074 let tx = f.validated_arc(MockTransaction::eip1559());
1076 let tx_id = *tx.id();
1077 pool.add_transaction(tx);
1078
1079 assert!(pool.contains(&tx_id));
1081
1082 let removed = pool.remove_transaction(&tx_id);
1084 assert!(removed.is_some());
1085 assert!(!pool.contains(&tx_id));
1086 }
1087
1088 #[test]
1089 fn test_enforce_basefee_with_handler_zero_allocation() {
1090 let mut f = MockTransactionFactory::default();
1091 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1092
1093 let sender_a = Address::with_last_byte(0x0a);
1095 let sender_b = Address::with_last_byte(0x0b);
1096
1097 let txs = vec![
1101 f.validated_arc(
1102 MockTransaction::eip1559()
1103 .set_sender(sender_a)
1104 .set_nonce(0)
1105 .set_max_fee(500)
1106 .clone(),
1107 ),
1108 f.validated_arc(
1109 MockTransaction::eip1559()
1110 .set_sender(sender_a)
1111 .set_nonce(1)
1112 .set_max_fee(600)
1113 .clone(),
1114 ),
1115 f.validated_arc(
1116 MockTransaction::eip1559()
1117 .set_sender(sender_b)
1118 .set_nonce(0)
1119 .set_max_fee(300)
1120 .clone(),
1121 ),
1122 ];
1123
1124 let expected_affordable = vec![txs[0].clone(), txs[1].clone()]; for tx in txs {
1126 pool.add_transaction(tx);
1127 }
1128
1129 let mut processed_txs = Vec::new();
1131 let mut handler_call_count = 0;
1132
1133 pool.enforce_basefee_with(400, |tx| {
1134 processed_txs.push(tx);
1135 handler_call_count += 1;
1136 });
1137
1138 assert_eq!(handler_call_count, 2);
1140 assert_eq!(processed_txs.len(), 2);
1141
1142 let processed_ids: Vec<_> = processed_txs.iter().map(|tx| *tx.id()).collect();
1144 for expected_tx in expected_affordable {
1145 assert!(processed_ids.contains(expected_tx.id()));
1146 }
1147
1148 assert_eq!(pool.len(), 1); }
1151}