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(
156 &self,
157 sender: SenderId,
158 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
159 self.by_id
160 .range((sender.start_bound(), Unbounded))
161 .take_while(move |(other, _)| sender == other.sender)
162 .map(|(_, tx)| Arc::clone(&tx.transaction))
163 .collect()
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 use super::*;
541 use crate::test_utils::{MockTransaction, MockTransactionFactory, MockTransactionSet};
542 use alloy_consensus::{Transaction, TxType};
543 use alloy_primitives::address;
544 use std::collections::HashSet;
545
546 #[test]
547 fn test_enforce_parked_basefee() {
548 let mut f = MockTransactionFactory::default();
549 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
550 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
551 pool.add_transaction(tx.clone());
552
553 assert!(pool.contains(tx.id()));
554 assert_eq!(pool.len(), 1);
555
556 let removed = pool.enforce_basefee(u64::MAX);
557 assert!(removed.is_empty());
558
559 let removed = pool.enforce_basefee((tx.max_fee_per_gas() - 1) as u64);
560 assert_eq!(removed.len(), 1);
561 assert!(pool.is_empty());
562 }
563
564 #[test]
565 fn test_enforce_parked_basefee_descendant() {
566 let mut f = MockTransactionFactory::default();
567 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
568 let t = MockTransaction::eip1559().inc_price_by(10);
569 let root_tx = f.validated_arc(t.clone());
570 pool.add_transaction(root_tx.clone());
571
572 let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
573 pool.add_transaction(descendant_tx.clone());
574
575 assert!(pool.contains(root_tx.id()));
576 assert!(pool.contains(descendant_tx.id()));
577 assert_eq!(pool.len(), 2);
578
579 let removed = pool.enforce_basefee(u64::MAX);
580 assert!(removed.is_empty());
581 assert_eq!(pool.len(), 2);
582 let removed = pool.enforce_basefee(descendant_tx.max_fee_per_gas() as u64);
586 assert_eq!(removed.len(), 2);
587 assert!(pool.is_empty());
588 }
589
590 #[test]
591 fn test_enforce_parked_basefee_removes_only_eligible_ancestor() {
592 let mut f = MockTransactionFactory::default();
593 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
594 let t = MockTransaction::eip1559().inc_price_by(10);
595
596 let root_tx = f.validated_arc(t.clone());
597 pool.add_transaction(root_tx.clone());
598
599 let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
600 pool.add_transaction(descendant_tx.clone());
601
602 let removed = pool.enforce_basefee(root_tx.max_fee_per_gas() as u64);
603
604 assert_eq!(removed.len(), 1);
605 assert_eq!(removed[0].id(), root_tx.id());
606 assert_eq!(pool.len(), 1);
607 assert!(!pool.contains(root_tx.id()));
608 assert!(pool.contains(descendant_tx.id()));
609 }
610
611 #[test]
612 fn truncate_parked_by_submission_id() {
613 let mut f = MockTransactionFactory::default();
615 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
616
617 let a_sender = address!("0x000000000000000000000000000000000000000a");
618 let b_sender = address!("0x000000000000000000000000000000000000000b");
619 let c_sender = address!("0x000000000000000000000000000000000000000c");
620 let d_sender = address!("0x000000000000000000000000000000000000000d");
621
622 let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
624 let a = tx_set.clone().into_vec();
625
626 let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
627 tx_set.extend(b.clone());
628
629 let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
631 tx_set.extend(c.clone());
632
633 let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
634 tx_set.extend(d.clone());
635
636 let all_txs = tx_set.into_vec();
637
638 let expected_parked = vec![c[0].clone(), c[1].clone(), c[2].clone(), d[0].clone()]
640 .into_iter()
641 .map(|tx| (tx.sender(), tx.nonce()))
642 .collect::<HashSet<_>>();
643
644 let expected_removed = vec![
648 a[0].clone(),
649 a[1].clone(),
650 a[2].clone(),
651 a[3].clone(),
652 b[0].clone(),
653 b[1].clone(),
654 b[2].clone(),
655 ]
656 .into_iter()
657 .map(|tx| (tx.sender(), tx.nonce()))
658 .collect::<HashSet<_>>();
659
660 for tx in all_txs {
662 pool.add_transaction(f.validated_arc(tx));
663 }
664
665 let pool_limit = SubPoolLimit { max_txs: 4, max_size: usize::MAX };
667
668 let removed = pool.truncate_pool(pool_limit);
670 assert_eq!(removed.len(), expected_removed.len());
671
672 let removed =
674 removed.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
675 assert_eq!(removed, expected_removed);
676
677 let parked = pool.all().collect::<Vec<_>>();
679 assert_eq!(parked.len(), expected_parked.len());
680
681 let parked = parked.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
683 assert_eq!(parked, expected_parked);
684 }
685
686 #[test]
687 fn test_truncate_parked_with_large_tx() {
688 let mut f = MockTransactionFactory::default();
689 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
690 let default_limits = SubPoolLimit::default();
691
692 let a_sender = address!("0x000000000000000000000000000000000000000a");
695
696 let a_txs = MockTransactionSet::dependent(a_sender, 0, 2, TxType::Eip1559)
698 .into_iter()
699 .map(|mut tx| {
700 tx.set_size(default_limits.max_size / 2 + 1);
701 tx
702 })
703 .collect::<Vec<_>>();
704
705 for tx in a_txs {
707 pool.add_transaction(f.validated_arc(tx));
708 }
709
710 let removed = pool.truncate_pool(default_limits);
712 assert_eq!(removed.len(), 1);
713 }
714
715 #[test]
716 fn test_senders_by_submission_id() {
717 let mut f = MockTransactionFactory::default();
719 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
720
721 let a_sender = address!("0x000000000000000000000000000000000000000a");
722 let b_sender = address!("0x000000000000000000000000000000000000000b");
723 let c_sender = address!("0x000000000000000000000000000000000000000c");
724 let d_sender = address!("0x000000000000000000000000000000000000000d");
725
726 let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
728 let a = tx_set.clone().into_vec();
729
730 let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
731 tx_set.extend(b.clone());
732
733 let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
735 tx_set.extend(c.clone());
736
737 let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
738 tx_set.extend(d.clone());
739
740 let all_txs = tx_set.into_vec();
741
742 for tx in all_txs {
744 pool.add_transaction(f.validated_arc(tx));
745 }
746
747 let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
749 assert_eq!(senders.len(), 4);
750 let expected_senders = vec![d_sender, c_sender, b_sender, a_sender]
751 .into_iter()
752 .map(|s| f.ids.sender_id(&s).unwrap())
753 .collect::<Vec<_>>();
754 assert_eq!(senders, expected_senders);
755
756 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
758 let all_txs = vec![d[0].clone(), b[0].clone(), c[0].clone(), a[0].clone()];
759
760 for tx in all_txs {
762 pool.add_transaction(f.validated_arc(tx));
763 }
764
765 let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
766 assert_eq!(senders.len(), 4);
767 let expected_senders = vec![a_sender, c_sender, b_sender, d_sender]
768 .into_iter()
769 .map(|s| f.ids.sender_id(&s).unwrap())
770 .collect::<Vec<_>>();
771 assert_eq!(senders, expected_senders);
772 }
773
774 #[test]
775 fn test_add_sender_count_new_sender() {
776 let mut f = MockTransactionFactory::default();
778 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
780 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
782 pool.add_transaction(tx);
783
784 let sender: SenderId = 11.into();
786 let submission_id = 1;
787
788 pool.add_sender_count(sender, submission_id);
790
791 assert_eq!(pool.sender_transaction_count.len(), 2);
793 let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
794 assert_eq!(sender_info.count, 1);
795 assert_eq!(sender_info.last_submission_id, submission_id);
796
797 assert_eq!(pool.last_sender_submission.len(), 2);
799 let submission_info = pool.last_sender_submission.iter().next().unwrap();
800 assert_eq!(submission_info.sender_id, sender);
801 assert_eq!(submission_info.submission_id, submission_id);
802 }
803
804 #[test]
805 fn test_add_sender_count_existing_sender() {
806 let mut f = MockTransactionFactory::default();
808 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
810 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
812 pool.add_transaction(tx);
813
814 let sender: SenderId = 11.into();
816 let initial_submission_id = 1;
817
818 pool.add_sender_count(sender, initial_submission_id);
820
821 let new_submission_id = 2;
823 pool.add_sender_count(sender, new_submission_id);
825
826 assert_eq!(pool.sender_transaction_count.len(), 2);
828 let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
829 assert_eq!(sender_info.count, 2);
830 assert_eq!(sender_info.last_submission_id, new_submission_id);
831
832 assert_eq!(pool.last_sender_submission.len(), 2);
834 let submission_info = pool.last_sender_submission.iter().next().unwrap();
835 assert_eq!(submission_info.sender_id, sender);
836 assert_eq!(submission_info.submission_id, new_submission_id);
837 }
838
839 #[test]
840 fn test_add_sender_count_multiple_senders() {
841 let mut f = MockTransactionFactory::default();
843 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
845 let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
847 let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
848 pool.add_transaction(tx1);
849 pool.add_transaction(tx2);
850
851 let sender1: SenderId = 11.into();
853 let sender2: SenderId = 22.into();
854
855 pool.add_sender_count(sender1, 1);
857 pool.add_sender_count(sender2, 2);
858
859 assert_eq!(pool.sender_transaction_count.len(), 4);
861
862 let sender1_info = pool.sender_transaction_count.get(&sender1).unwrap();
863 assert_eq!(sender1_info.count, 1);
864 assert_eq!(sender1_info.last_submission_id, 1);
865
866 let sender2_info = pool.sender_transaction_count.get(&sender2).unwrap();
867 assert_eq!(sender2_info.count, 1);
868 assert_eq!(sender2_info.last_submission_id, 2);
869
870 assert_eq!(pool.last_sender_submission.len(), 3);
872
873 let submission_info1 =
875 pool.last_sender_submission.iter().find(|info| info.sender_id == sender1);
876 assert!(submission_info1.is_none());
877
878 let submission_info2 =
880 pool.last_sender_submission.iter().find(|info| info.sender_id == sender2).unwrap();
881 assert_eq!(submission_info2.sender_id, sender2);
882 assert_eq!(submission_info2.submission_id, 2);
883 }
884
885 #[test]
886 fn test_remove_sender_count() {
887 let mut f = MockTransactionFactory::default();
889 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
891 let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
893 let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
894 pool.add_transaction(tx1);
895 pool.add_transaction(tx2);
896
897 let sender1: SenderId = 11.into();
899 let sender2: SenderId = 22.into();
900
901 pool.add_sender_count(sender1, 1);
903
904 pool.add_sender_count(sender2, 2);
906 pool.add_sender_count(sender2, 3);
907
908 assert_eq!(pool.sender_transaction_count.len(), 4);
910 assert!(pool.sender_transaction_count.contains_key(&sender1));
911
912 assert_eq!(pool.sender_transaction_count.get(&sender1).unwrap().count, 1);
914
915 pool.remove_sender_count(sender1);
917
918 assert_eq!(pool.sender_transaction_count.len(), 3);
920 assert!(!pool.sender_transaction_count.contains_key(&sender1));
921
922 assert_eq!(
924 *pool.sender_transaction_count.get(&sender2).unwrap(),
925 SenderTransactionCount { count: 2, last_submission_id: 3 }
926 );
927
928 pool.remove_sender_count(sender2);
930
931 assert_eq!(pool.sender_transaction_count.len(), 3);
936 assert!(pool.sender_transaction_count.contains_key(&sender2));
937
938 assert_eq!(
940 *pool.sender_transaction_count.get(&sender2).unwrap(),
941 SenderTransactionCount { count: 1, last_submission_id: 3 }
942 );
943 }
944
945 #[test]
946 fn test_pool_size() {
947 let mut f = MockTransactionFactory::default();
948 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
949
950 let tx = f.validated_arc(MockTransaction::eip1559().set_size(1024).clone());
952 pool.add_transaction(tx);
953
954 assert_eq!(pool.size(), 1024);
956 }
957
958 #[test]
959 fn test_pool_len() {
960 let mut f = MockTransactionFactory::default();
961 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
962
963 assert_eq!(pool.len(), 0);
965
966 let tx = f.validated_arc(MockTransaction::eip1559());
968 pool.add_transaction(tx);
969 assert_eq!(pool.len(), 1);
970 }
971
972 #[test]
973 fn test_pool_contains() {
974 let mut f = MockTransactionFactory::default();
975 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
976
977 let tx = f.validated_arc(MockTransaction::eip1559());
979 let tx_id = *tx.id();
980
981 assert!(!pool.contains(&tx_id));
983
984 pool.add_transaction(tx);
986 assert!(pool.contains(&tx_id));
987 }
988
989 #[test]
990 fn test_get_transaction() {
991 let mut f = MockTransactionFactory::default();
992 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
993
994 let tx = f.validated_arc(MockTransaction::eip1559());
996 let tx_id = *tx.id();
997 pool.add_transaction(tx.clone());
998
999 let retrieved = pool.get(&tx_id).expect("Transaction should exist in the pool");
1001 assert_eq!(retrieved.transaction.id(), tx.id());
1002 }
1003
1004 #[test]
1005 fn test_all_transactions() {
1006 let mut f = MockTransactionFactory::default();
1007 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1008
1009 let tx1 = f.validated_arc(MockTransaction::eip1559());
1011 let tx2 = f.validated_arc(MockTransaction::eip1559());
1012 pool.add_transaction(tx1.clone());
1013 pool.add_transaction(tx2.clone());
1014
1015 let all_txs: Vec<_> = pool.all().map(|tx| *tx.id()).collect();
1017 assert_eq!(all_txs.len(), 2);
1018
1019 assert!(all_txs.contains(tx1.id()));
1021 assert!(all_txs.contains(tx2.id()));
1022 }
1023
1024 #[test]
1025 fn test_truncate_pool_edge_case() {
1026 let mut f = MockTransactionFactory::default();
1027 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1028
1029 let tx1 = f.validated_arc(MockTransaction::eip1559());
1031 let tx2 = f.validated_arc(MockTransaction::eip1559());
1032 pool.add_transaction(tx1);
1033 pool.add_transaction(tx2);
1034
1035 let limit = SubPoolLimit { max_txs: 2, max_size: usize::MAX };
1037 let removed = pool.truncate_pool(limit);
1038
1039 assert!(removed.is_empty());
1041
1042 let limit = SubPoolLimit { max_txs: 1, max_size: usize::MAX };
1044 let removed = pool.truncate_pool(limit);
1045
1046 assert_eq!(removed.len(), 1);
1048 assert_eq!(pool.len(), 1);
1049 }
1050
1051 #[test]
1052 fn test_satisfy_base_fee_transactions() {
1053 let mut f = MockTransactionFactory::default();
1054 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1055
1056 let tx1 = f.validated_arc(MockTransaction::eip1559().set_max_fee(100).clone());
1058 let tx2 = f.validated_arc(MockTransaction::eip1559().set_max_fee(200).clone());
1059 pool.add_transaction(tx1);
1060 pool.add_transaction(tx2.clone());
1061
1062 let satisfied = pool.satisfy_base_fee_transactions(150);
1064 assert_eq!(satisfied.len(), 1);
1065 assert_eq!(satisfied[0].id(), tx2.id())
1066 }
1067
1068 #[test]
1069 fn test_remove_transaction() {
1070 let mut f = MockTransactionFactory::default();
1071 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1072
1073 let tx = f.validated_arc(MockTransaction::eip1559());
1075 let tx_id = *tx.id();
1076 pool.add_transaction(tx);
1077
1078 assert!(pool.contains(&tx_id));
1080
1081 let removed = pool.remove_transaction(&tx_id);
1083 assert!(removed.is_some());
1084 assert!(!pool.contains(&tx_id));
1085 }
1086
1087 #[test]
1088 fn test_enforce_basefee_with_handler_zero_allocation() {
1089 let mut f = MockTransactionFactory::default();
1090 let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1091
1092 let sender_a = address!("0x000000000000000000000000000000000000000a");
1094 let sender_b = address!("0x000000000000000000000000000000000000000b");
1095
1096 let txs = vec![
1100 f.validated_arc(
1101 MockTransaction::eip1559()
1102 .set_sender(sender_a)
1103 .set_nonce(0)
1104 .set_max_fee(500)
1105 .clone(),
1106 ),
1107 f.validated_arc(
1108 MockTransaction::eip1559()
1109 .set_sender(sender_a)
1110 .set_nonce(1)
1111 .set_max_fee(600)
1112 .clone(),
1113 ),
1114 f.validated_arc(
1115 MockTransaction::eip1559()
1116 .set_sender(sender_b)
1117 .set_nonce(0)
1118 .set_max_fee(300)
1119 .clone(),
1120 ),
1121 ];
1122
1123 let expected_affordable = vec![txs[0].clone(), txs[1].clone()]; for tx in txs {
1125 pool.add_transaction(tx);
1126 }
1127
1128 let mut processed_txs = Vec::new();
1130 let mut handler_call_count = 0;
1131
1132 pool.enforce_basefee_with(400, |tx| {
1133 processed_txs.push(tx);
1134 handler_call_count += 1;
1135 });
1136
1137 assert_eq!(handler_call_count, 2);
1139 assert_eq!(processed_txs.len(), 2);
1140
1141 let processed_ids: Vec<_> = processed_txs.iter().map(|tx| *tx.id()).collect();
1143 for expected_tx in expected_affordable {
1144 assert!(processed_ids.contains(expected_tx.id()));
1145 }
1146
1147 assert_eq!(pool.len(), 1); }
1150}