reth_transaction_pool/pool/
pending.rs1use crate::{
4 identifier::{SenderId, TransactionId},
5 pool::{
6 best::{BestTransactions, BestTransactionsWithFees},
7 size::SizeTracker,
8 },
9 Priority, SubPoolLimit, TransactionOrdering, ValidPoolTransaction,
10};
11use rustc_hash::{FxHashMap, FxHashSet};
12use std::{
13 cmp::Ordering,
14 collections::{hash_map::Entry, BTreeMap},
15 ops::Bound::Unbounded,
16 sync::Arc,
17};
18use tokio::sync::broadcast;
19
20#[derive(Debug, Clone)]
31pub struct PendingPool<T: TransactionOrdering> {
32 ordering: T,
34 submission_id: u64,
38 by_id: BTreeMap<TransactionId, PendingTransaction<T>>,
40 highest_nonces: FxHashMap<SenderId, PendingTransaction<T>>,
43 independent_transactions: FxHashMap<SenderId, PendingTransaction<T>>,
46 size_of: SizeTracker,
50 new_transaction_notifier: broadcast::Sender<PendingTransaction<T>>,
53}
54
55impl<T: TransactionOrdering> PendingPool<T> {
58 pub fn new(ordering: T) -> Self {
60 Self::with_buffer(ordering, 200)
61 }
62
63 pub fn with_buffer(ordering: T, buffer_capacity: usize) -> Self {
65 let (new_transaction_notifier, _) = broadcast::channel(buffer_capacity);
66 Self {
67 ordering,
68 submission_id: 0,
69 by_id: Default::default(),
70 independent_transactions: Default::default(),
71 highest_nonces: Default::default(),
72 size_of: Default::default(),
73 new_transaction_notifier,
74 }
75 }
76
77 fn clear_transactions(&mut self) -> BTreeMap<TransactionId, PendingTransaction<T>> {
84 self.independent_transactions.clear();
85 self.highest_nonces.clear();
86 self.size_of.reset();
87 std::mem::take(&mut self.by_id)
88 }
89
90 pub fn best(&self) -> BestTransactions<T> {
109 BestTransactions {
110 all: self.by_id.clone(),
111 independent: self.independent_transactions.values().cloned().collect(),
112 invalid: Default::default(),
113 new_transaction_receiver: Some(self.new_transaction_notifier.subscribe()),
114 last_priority: None,
115 skip_blobs: false,
116 }
117 }
118
119 pub(crate) fn best_with_basefee_and_blobfee(
121 &self,
122 base_fee: u64,
123 base_fee_per_blob_gas: u64,
124 ) -> BestTransactionsWithFees<T> {
125 BestTransactionsWithFees { best: self.best(), base_fee, base_fee_per_blob_gas }
126 }
127
128 pub(crate) fn best_with_unlocked_and_attributes(
139 &self,
140 unlocked: Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
141 base_fee: u64,
142 base_fee_per_blob_gas: u64,
143 ) -> BestTransactionsWithFees<T> {
144 let mut best = self.best();
145 let mut submission_id = self.submission_id;
146 for tx in unlocked {
147 submission_id += 1;
148 debug_assert!(!best.all.contains_key(tx.id()), "transaction already included");
149 let priority = self.ordering.priority(&tx.transaction, base_fee);
150 let tx_id = *tx.id();
151 let transaction = PendingTransaction { submission_id, transaction: tx, priority };
152 if best.ancestor(&tx_id).is_none() {
153 best.independent.insert(transaction.clone());
154 }
155 best.all.insert(tx_id, transaction);
156 }
157
158 BestTransactionsWithFees { best, base_fee, base_fee_per_blob_gas }
159 }
160
161 pub(crate) fn all(
163 &self,
164 ) -> impl ExactSizeIterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
165 self.by_id.values().map(|tx| tx.transaction.clone())
166 }
167
168 pub(crate) fn update_blob_fee(
178 &mut self,
179 blob_fee: u128,
180 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
181 let mut removed = Vec::new();
183
184 let mut transactions_iter = self.clear_transactions().into_iter().peekable();
186 while let Some((id, tx)) = transactions_iter.next() {
187 if tx.transaction.is_eip4844() && tx.transaction.max_fee_per_blob_gas() < Some(blob_fee)
188 {
189 removed.push(Arc::clone(&tx.transaction));
192
193 'this: while let Some((next_id, next_tx)) = transactions_iter.peek() {
195 if next_id.sender != id.sender {
196 break 'this
197 }
198 removed.push(Arc::clone(&next_tx.transaction));
199 transactions_iter.next();
200 }
201 } else {
202 self.size_of += tx.transaction.size();
203 self.update_independents_and_highest_nonces(&tx);
204 self.by_id.insert(id, tx);
205 }
206 }
207
208 removed
209 }
210
211 pub(crate) fn update_base_fee(
221 &mut self,
222 base_fee: u64,
223 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
224 let mut removed = Vec::new();
226
227 let mut transactions_iter = self.clear_transactions().into_iter().peekable();
229 while let Some((id, mut tx)) = transactions_iter.next() {
230 if tx.transaction.max_fee_per_gas() < base_fee as u128 {
231 removed.push(Arc::clone(&tx.transaction));
234
235 'this: while let Some((next_id, next_tx)) = transactions_iter.peek() {
237 if next_id.sender != id.sender {
238 break 'this
239 }
240 removed.push(Arc::clone(&next_tx.transaction));
241 transactions_iter.next();
242 }
243 } else {
244 tx.priority = self.ordering.priority(&tx.transaction.transaction, base_fee);
246
247 self.size_of += tx.transaction.size();
248 self.update_independents_and_highest_nonces(&tx);
249 self.by_id.insert(id, tx);
250 }
251 }
252
253 removed
254 }
255
256 fn update_independents_and_highest_nonces(&mut self, tx: &PendingTransaction<T>) {
259 match self.highest_nonces.entry(tx.transaction.sender_id()) {
260 Entry::Occupied(mut entry) => {
261 if entry.get().transaction.nonce() < tx.transaction.nonce() {
262 *entry.get_mut() = tx.clone();
263 }
264 }
265 Entry::Vacant(entry) => {
266 entry.insert(tx.clone());
267 }
268 }
269 match self.independent_transactions.entry(tx.transaction.sender_id()) {
270 Entry::Occupied(mut entry) => {
271 if entry.get().transaction.nonce() > tx.transaction.nonce() {
272 *entry.get_mut() = tx.clone();
273 }
274 }
275 Entry::Vacant(entry) => {
276 entry.insert(tx.clone());
277 }
278 }
279 }
280
281 fn ancestor(&self, id: &TransactionId) -> Option<&PendingTransaction<T>> {
286 self.get(&id.unchecked_ancestor()?)
287 }
288
289 pub fn add_transaction(
295 &mut self,
296 tx: Arc<ValidPoolTransaction<T::Transaction>>,
297 base_fee: u64,
298 ) {
299 debug_assert!(
300 !self.contains(tx.id()),
301 "transaction already included {:?}",
302 self.get(tx.id()).unwrap().transaction
303 );
304
305 self.size_of += tx.size();
307
308 let tx_id = *tx.id();
309
310 let submission_id = self.next_id();
311 let priority = self.ordering.priority(&tx.transaction, base_fee);
312 let tx = PendingTransaction { submission_id, transaction: tx, priority };
313
314 self.update_independents_and_highest_nonces(&tx);
315
316 if self.new_transaction_notifier.receiver_count() > 0 {
318 let _ = self.new_transaction_notifier.send(tx.clone());
319 }
320
321 self.by_id.insert(tx_id, tx);
322 }
323
324 pub(crate) fn remove_transaction(
329 &mut self,
330 id: &TransactionId,
331 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
332 if let Some(lowest) = self.independent_transactions.get(&id.sender) &&
333 lowest.transaction.nonce() == id.nonce
334 {
335 self.independent_transactions.remove(&id.sender);
336 if let Some(unlocked) = self.get(&id.descendant()) {
338 self.independent_transactions.insert(id.sender, unlocked.clone());
339 }
340 }
341
342 let tx = self.by_id.remove(id)?;
343 self.size_of -= tx.transaction.size();
344
345 if let Some(highest) = self.highest_nonces.get(&id.sender) {
346 if highest.transaction.nonce() == id.nonce {
347 self.highest_nonces.remove(&id.sender);
348 }
349 if let Some(ancestor) = self.ancestor(id) {
350 self.highest_nonces.insert(id.sender, ancestor.clone());
351 }
352 }
353 Some(tx.transaction)
354 }
355
356 const fn next_id(&mut self) -> u64 {
357 let id = self.submission_id;
358 self.submission_id = self.submission_id.wrapping_add(1);
359 id
360 }
361
362 pub fn remove_to_limit(
377 &mut self,
378 limit: &SubPoolLimit,
379 remove_locals: bool,
380 end_removed: &mut Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
381 ) {
382 let mut non_local_senders = self.highest_nonces.len();
391
392 let mut unique_senders = self.highest_nonces.len();
395
396 let mut local_senders = FxHashSet::default();
398
399 let original_length = self.len();
401 let mut removed = Vec::new();
402 let mut total_removed = 0;
403
404 let original_size = self.size();
406 let mut total_size = 0;
407
408 loop {
409 let unique_removed = unique_senders - self.highest_nonces.len();
411
412 unique_senders = self.highest_nonces.len();
414 non_local_senders -= unique_removed;
415
416 removed.clear();
418
419 let mut worst_transactions = self.highest_nonces.values().collect::<Vec<_>>();
421 worst_transactions.sort();
422
423 for tx in worst_transactions {
425 if !limit.is_exceeded(original_length - total_removed, original_size - total_size) ||
427 non_local_senders == 0
428 {
429 for id in &removed {
431 if let Some(tx) = self.remove_transaction(id) {
432 end_removed.push(tx);
433 }
434 }
435
436 return
437 }
438
439 if !remove_locals && tx.transaction.is_local() {
440 let sender_id = tx.transaction.sender_id();
441 if local_senders.insert(sender_id) {
442 non_local_senders -= 1;
443 }
444 continue
445 }
446
447 total_size += tx.transaction.size();
448 total_removed += 1;
449 removed.push(*tx.transaction.id());
450 }
451
452 for id in &removed {
454 if let Some(tx) = self.remove_transaction(id) {
455 end_removed.push(tx);
456 }
457 }
458
459 if !self.exceeds(limit) || non_local_senders == 0 {
462 return
463 }
464 }
465 }
466
467 pub fn truncate_pool(
478 &mut self,
479 limit: SubPoolLimit,
480 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
481 let mut removed = Vec::new();
482 if !self.exceeds(&limit) {
484 return removed
485 }
486
487 self.remove_to_limit(&limit, false, &mut removed);
489 if !self.exceeds(&limit) {
490 return removed
491 }
492
493 self.remove_to_limit(&limit, true, &mut removed);
496
497 removed
498 }
499
500 #[inline]
502 pub(crate) fn exceeds(&self, limit: &SubPoolLimit) -> bool {
503 limit.is_exceeded(self.len(), self.size())
504 }
505
506 pub(crate) fn size(&self) -> usize {
508 self.size_of.into()
509 }
510
511 pub(crate) fn len(&self) -> usize {
513 self.by_id.len()
514 }
515
516 pub const fn by_id(&self) -> &BTreeMap<TransactionId, PendingTransaction<T>> {
518 &self.by_id
519 }
520
521 pub const fn independent_transactions(&self) -> &FxHashMap<SenderId, PendingTransaction<T>> {
523 &self.independent_transactions
524 }
525
526 pub fn new_transaction_receiver(&self) -> broadcast::Receiver<PendingTransaction<T>> {
528 self.new_transaction_notifier.subscribe()
529 }
530
531 #[cfg(test)]
533 pub(crate) fn is_empty(&self) -> bool {
534 self.by_id.is_empty()
535 }
536
537 pub(crate) fn contains(&self, id: &TransactionId) -> bool {
539 self.by_id.contains_key(id)
540 }
541
542 pub(crate) fn get_txs_by_sender(&self, sender: SenderId) -> Vec<TransactionId> {
544 self.iter_txs_by_sender(sender).copied().collect()
545 }
546
547 pub(crate) fn iter_txs_by_sender(
549 &self,
550 sender: SenderId,
551 ) -> impl Iterator<Item = &TransactionId> + '_ {
552 self.by_id
553 .range((sender.start_bound(), Unbounded))
554 .take_while(move |(other, _)| sender == other.sender)
555 .map(|(tx_id, _)| tx_id)
556 }
557
558 fn get(&self, id: &TransactionId) -> Option<&PendingTransaction<T>> {
560 self.by_id.get(id)
561 }
562
563 #[cfg(test)]
565 pub(crate) const fn independent(&self) -> &FxHashMap<SenderId, PendingTransaction<T>> {
566 &self.independent_transactions
567 }
568
569 #[cfg(any(test, feature = "test-utils"))]
571 pub(crate) fn assert_invariants(&self) {
572 assert!(
573 self.independent_transactions.len() <= self.by_id.len(),
574 "independent_transactions.len() > by_id.len()"
575 );
576 assert!(
577 self.highest_nonces.len() <= self.by_id.len(),
578 "highest_nonces.len() > by_id.len()"
579 );
580 assert_eq!(
581 self.highest_nonces.len(),
582 self.independent_transactions.len(),
583 "highest_nonces.len() != independent_transactions.len()"
584 );
585 }
586}
587
588#[derive(Debug)]
590pub struct PendingTransaction<T: TransactionOrdering> {
591 pub submission_id: u64,
593 pub transaction: Arc<ValidPoolTransaction<T::Transaction>>,
595 pub priority: Priority<T::PriorityValue>,
597}
598
599impl<T: TransactionOrdering> PendingTransaction<T> {
600 pub fn unlocks(&self) -> TransactionId {
602 self.transaction.transaction_id.descendant()
603 }
604}
605
606impl<T: TransactionOrdering> Clone for PendingTransaction<T> {
607 fn clone(&self) -> Self {
608 Self {
609 submission_id: self.submission_id,
610 transaction: Arc::clone(&self.transaction),
611 priority: self.priority.clone(),
612 }
613 }
614}
615
616impl<T: TransactionOrdering> Eq for PendingTransaction<T> {}
617
618impl<T: TransactionOrdering> PartialEq<Self> for PendingTransaction<T> {
619 fn eq(&self, other: &Self) -> bool {
620 self.cmp(other) == Ordering::Equal
621 }
622}
623
624impl<T: TransactionOrdering> PartialOrd<Self> for PendingTransaction<T> {
625 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
626 Some(self.cmp(other))
627 }
628}
629
630impl<T: TransactionOrdering> Ord for PendingTransaction<T> {
631 fn cmp(&self, other: &Self) -> Ordering {
632 self.priority
636 .cmp(&other.priority)
637 .then_with(|| other.submission_id.cmp(&self.submission_id))
638 }
639}
640
641#[cfg(test)]
642mod tests {
643 use super::*;
644 use crate::{
645 test_utils::{MockOrdering, MockTransaction, MockTransactionFactory, MockTransactionSet},
646 PoolTransaction,
647 };
648 use alloy_consensus::{Transaction, TxType};
649 use alloy_primitives::address;
650 use std::collections::HashSet;
651
652 #[test]
653 fn test_enforce_basefee() {
654 let mut f = MockTransactionFactory::default();
655 let mut pool = PendingPool::new(MockOrdering::default());
656 let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
657 pool.add_transaction(tx.clone(), 0);
658
659 assert!(pool.contains(tx.id()));
660 assert_eq!(pool.len(), 1);
661
662 let removed = pool.update_base_fee(0);
663 assert!(removed.is_empty());
664
665 let removed = pool.update_base_fee((tx.max_fee_per_gas() + 1) as u64);
666 assert_eq!(removed.len(), 1);
667 assert!(pool.is_empty());
668 }
669
670 #[test]
671 fn test_enforce_basefee_descendant() {
672 let mut f = MockTransactionFactory::default();
673 let mut pool = PendingPool::new(MockOrdering::default());
674 let t = MockTransaction::eip1559().inc_price_by(10);
675 let root_tx = f.validated_arc(t.clone());
676 pool.add_transaction(root_tx.clone(), 0);
677
678 let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
679 pool.add_transaction(descendant_tx.clone(), 0);
680
681 assert!(pool.contains(root_tx.id()));
682 assert!(pool.contains(descendant_tx.id()));
683 assert_eq!(pool.len(), 2);
684
685 assert_eq!(pool.independent_transactions.len(), 1);
686 assert_eq!(pool.highest_nonces.len(), 1);
687
688 let removed = pool.update_base_fee(0);
689 assert!(removed.is_empty());
690
691 {
694 let mut pool2 = pool.clone();
695 let removed = pool2.update_base_fee((descendant_tx.max_fee_per_gas() + 1) as u64);
696 assert_eq!(removed.len(), 1);
697 assert_eq!(pool2.len(), 1);
698 assert!(pool2.contains(root_tx.id()));
700 assert!(!pool2.contains(descendant_tx.id()));
701 }
702
703 let removed = pool.update_base_fee((root_tx.max_fee_per_gas() + 1) as u64);
705 assert_eq!(removed.len(), 2);
706 assert!(pool.is_empty());
707 pool.assert_invariants();
708 }
709
710 #[test]
711 fn evict_worst() {
712 let mut f = MockTransactionFactory::default();
713 let mut pool = PendingPool::new(MockOrdering::default());
714
715 let t = MockTransaction::eip1559();
716 pool.add_transaction(f.validated_arc(t.clone()), 0);
717
718 let t2 = MockTransaction::eip1559().inc_price_by(10);
719 pool.add_transaction(f.validated_arc(t2), 0);
720
721 assert_eq!(
723 pool.highest_nonces.values().min().map(|tx| *tx.transaction.hash()),
724 Some(*t.hash())
725 );
726
727 let removed = pool.truncate_pool(SubPoolLimit { max_txs: 1, max_size: usize::MAX });
729 assert_eq!(removed.len(), 1);
730 assert_eq!(removed[0].hash(), t.hash());
731 }
732
733 #[test]
734 fn correct_independent_descendants() {
735 let mut f = MockTransactionFactory::default();
737 let mut pool = PendingPool::new(MockOrdering::default());
738
739 let a_sender = address!("0x000000000000000000000000000000000000000a");
740 let b_sender = address!("0x000000000000000000000000000000000000000b");
741 let c_sender = address!("0x000000000000000000000000000000000000000c");
742 let d_sender = address!("0x000000000000000000000000000000000000000d");
743
744 let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
746 let a = tx_set.clone().into_vec();
747
748 let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
749 tx_set.extend(b.clone());
750
751 let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
753 tx_set.extend(c.clone());
754
755 let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
756 tx_set.extend(d.clone());
757
758 let all_txs = tx_set.into_vec();
760 for tx in all_txs {
761 pool.add_transaction(f.validated_arc(tx), 0);
762 }
763
764 pool.assert_invariants();
765
766 let expected_highest_nonces = [d[0].clone(), c[2].clone(), b[2].clone(), a[3].clone()]
769 .iter()
770 .map(|tx| (tx.sender(), tx.nonce()))
771 .collect::<HashSet<_>>();
772 let actual_highest_nonces = pool
773 .highest_nonces
774 .values()
775 .map(|tx| (tx.transaction.sender(), tx.transaction.nonce()))
776 .collect::<HashSet<_>>();
777 assert_eq!(expected_highest_nonces, actual_highest_nonces);
778 pool.assert_invariants();
779 }
780
781 #[test]
782 fn truncate_by_sender() {
783 let mut f = MockTransactionFactory::default();
785 let mut pool = PendingPool::new(MockOrdering::default());
786
787 let a = address!("0x000000000000000000000000000000000000000a");
789 let b = address!("0x000000000000000000000000000000000000000b");
790 let c = address!("0x000000000000000000000000000000000000000c");
791 let d = address!("0x000000000000000000000000000000000000000d");
792
793 let a_txs = MockTransactionSet::sequential_transactions_by_sender(a, 4, TxType::Eip1559);
795 let b_txs = MockTransactionSet::sequential_transactions_by_sender(b, 3, TxType::Eip1559);
796 let c_txs = MockTransactionSet::sequential_transactions_by_sender(c, 3, TxType::Eip1559);
797 let d_txs = MockTransactionSet::sequential_transactions_by_sender(d, 1, TxType::Eip1559);
798
799 let expected_pending = vec![
801 a_txs.transactions[0].clone(),
802 b_txs.transactions[0].clone(),
803 c_txs.transactions[0].clone(),
804 a_txs.transactions[1].clone(),
805 ]
806 .into_iter()
807 .map(|tx| (tx.sender(), tx.nonce()))
808 .collect::<HashSet<_>>();
809
810 let expected_removed = vec![
812 d_txs.transactions[0].clone(),
813 c_txs.transactions[2].clone(),
814 b_txs.transactions[2].clone(),
815 a_txs.transactions[3].clone(),
816 c_txs.transactions[1].clone(),
817 b_txs.transactions[1].clone(),
818 a_txs.transactions[2].clone(),
819 ]
820 .into_iter()
821 .map(|tx| (tx.sender(), tx.nonce()))
822 .collect::<HashSet<_>>();
823
824 let all_txs =
826 [a_txs.into_vec(), b_txs.into_vec(), c_txs.into_vec(), d_txs.into_vec()].concat();
827
828 for tx in all_txs {
830 pool.add_transaction(f.validated_arc(tx), 0);
831 }
832
833 pool.assert_invariants();
835
836 let pool_limit = SubPoolLimit { max_txs: 4, max_size: usize::MAX };
846
847 let removed = pool.truncate_pool(pool_limit);
849 pool.assert_invariants();
850 assert_eq!(removed.len(), expected_removed.len());
851
852 let removed =
854 removed.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
855 assert_eq!(removed, expected_removed);
856
857 let pending = pool.all().collect::<Vec<_>>();
859 assert_eq!(pending.len(), expected_pending.len());
860
861 let pending =
863 pending.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
864 assert_eq!(pending, expected_pending);
865 }
866
867 #[test]
869 fn test_eligible_updates_promoted() {
870 let mut pool = PendingPool::new(MockOrdering::default());
871 let mut f = MockTransactionFactory::default();
872
873 let num_senders = 10;
874
875 let first_txs: Vec<_> = (0..num_senders) .map(|_| MockTransaction::eip1559())
877 .collect();
878 let second_txs: Vec<_> =
879 first_txs.iter().map(|tx| tx.clone().rng_hash().inc_nonce()).collect();
880
881 for tx in first_txs {
882 let valid_tx = f.validated(tx);
883 pool.add_transaction(Arc::new(valid_tx), 0);
884 }
885
886 let mut best = pool.best();
887
888 for _ in 0..num_senders {
889 if let Some(tx) = best.next() {
890 assert_eq!(tx.nonce(), 0);
891 } else {
892 panic!("cannot read one of first_txs");
893 }
894 }
895
896 for tx in second_txs {
897 let valid_tx = f.validated(tx);
898 pool.add_transaction(Arc::new(valid_tx), 0);
899 }
900
901 for _ in 0..num_senders {
902 if let Some(tx) = best.next() {
903 assert_eq!(tx.nonce(), 1);
904 } else {
905 panic!("cannot read one of second_txs");
906 }
907 }
908 }
909
910 #[test]
911 fn test_empty_pool_behavior() {
912 let mut pool = PendingPool::<MockOrdering>::new(MockOrdering::default());
913
914 assert!(pool.is_empty());
916 assert_eq!(pool.len(), 0);
917 assert_eq!(pool.size(), 0);
918
919 let removed = pool.truncate_pool(SubPoolLimit { max_txs: 10, max_size: 1000 });
921 assert!(removed.is_empty());
922
923 assert!(pool.all().next().is_none());
925 }
926
927 #[test]
928 fn test_add_remove_transaction() {
929 let mut f = MockTransactionFactory::default();
930 let mut pool = PendingPool::new(MockOrdering::default());
931
932 let tx = f.validated_arc(MockTransaction::eip1559());
934 pool.add_transaction(tx.clone(), 0);
935 assert!(pool.contains(tx.id()));
936 assert_eq!(pool.len(), 1);
937
938 let removed_tx = pool.remove_transaction(tx.id()).unwrap();
940 assert_eq!(removed_tx.id(), tx.id());
941 assert!(!pool.contains(tx.id()));
942 assert_eq!(pool.len(), 0);
943 }
944
945 #[test]
946 fn test_reorder_on_basefee_update() {
947 let mut f = MockTransactionFactory::default();
948 let mut pool = PendingPool::new(MockOrdering::default());
949
950 let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
952 let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price_by(20));
953 pool.add_transaction(tx1.clone(), 0);
954 pool.add_transaction(tx2.clone(), 0);
955
956 let mut best = pool.best();
958 assert_eq!(best.next().unwrap().hash(), tx2.hash());
959 assert_eq!(best.next().unwrap().hash(), tx1.hash());
960
961 let removed = pool.update_base_fee((tx1.max_fee_per_gas() + 1) as u64);
963 assert_eq!(removed.len(), 1);
964 assert_eq!(removed[0].hash(), tx1.hash());
965
966 assert_eq!(pool.len(), 1);
968 assert!(pool.contains(tx2.id()));
969 assert!(!pool.contains(tx1.id()));
970 }
971
972 #[test]
973 #[should_panic(expected = "transaction already included")]
974 fn test_handle_duplicates() {
975 let mut f = MockTransactionFactory::default();
976 let mut pool = PendingPool::new(MockOrdering::default());
977
978 let tx = f.validated_arc(MockTransaction::eip1559());
980 pool.add_transaction(tx.clone(), 0);
981 assert!(pool.contains(tx.id()));
982 assert_eq!(pool.len(), 1);
983
984 pool.add_transaction(tx, 0);
986 }
987
988 #[test]
989 fn test_update_blob_fee() {
990 let mut f = MockTransactionFactory::default();
991 let mut pool = PendingPool::new(MockOrdering::default());
992
993 let tx1 = f.validated_arc(MockTransaction::eip4844().set_blob_fee(50).clone());
995 let tx2 = f.validated_arc(MockTransaction::eip4844().set_blob_fee(150).clone());
996 pool.add_transaction(tx1.clone(), 0);
997 pool.add_transaction(tx2.clone(), 0);
998
999 let removed = pool.update_blob_fee(100);
1001 assert_eq!(removed.len(), 1);
1002 assert_eq!(removed[0].hash(), tx1.hash());
1003
1004 assert!(pool.contains(tx2.id()));
1006 assert!(!pool.contains(tx1.id()));
1007 }
1008
1009 #[test]
1010 fn local_senders_tracking() {
1011 let mut f = MockTransactionFactory::default();
1012 let mut pool = PendingPool::new(MockOrdering::default());
1013
1014 let a = address!("0x000000000000000000000000000000000000000a");
1016 let b = address!("0x000000000000000000000000000000000000000b");
1017 let c = address!("0x000000000000000000000000000000000000000c");
1018
1019 let a_txs = MockTransactionSet::sequential_transactions_by_sender(a, 11, TxType::Eip1559);
1025 let b_txs = MockTransactionSet::sequential_transactions_by_sender(b, 2, TxType::Eip1559);
1026 let c_txs = MockTransactionSet::sequential_transactions_by_sender(c, 2, TxType::Eip1559);
1027
1028 for tx in a_txs.into_vec() {
1030 let final_tx = Arc::new(f.validated_with_origin(crate::TransactionOrigin::Local, tx));
1031
1032 pool.add_transaction(final_tx, 0);
1033 }
1034
1035 let remaining_txs = [b_txs.into_vec(), c_txs.into_vec()].concat();
1037 for tx in remaining_txs {
1038 let final_tx = f.validated_arc(tx);
1039
1040 pool.add_transaction(final_tx, 0);
1041 }
1042
1043 pool.assert_invariants();
1045
1046 let pool_limit = SubPoolLimit { max_txs: 10, max_size: usize::MAX };
1047 pool.truncate_pool(pool_limit);
1048
1049 let sender_a = f.ids.sender_id(&a).unwrap();
1050 let sender_b = f.ids.sender_id(&b).unwrap();
1051 let sender_c = f.ids.sender_id(&c).unwrap();
1052
1053 assert_eq!(pool.get_txs_by_sender(sender_a).len(), 10);
1054 assert!(pool.get_txs_by_sender(sender_b).is_empty());
1055 assert!(pool.get_txs_by_sender(sender_c).is_empty());
1056 }
1057}