reth_transaction_pool/pool/
parked.rs

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/// A pool of transactions that are currently parked and are waiting for external changes (e.g.
16/// basefee, ancestor transactions, balance) that eventually move the transaction into the pending
17/// pool.
18///
19/// This pool is a bijection: at all times each set (`best`, `by_id`) contains the same
20/// transactions.
21///
22/// Note: This type is generic over [`ParkedPool`] which enforces that the underlying transaction
23/// type is [`ValidPoolTransaction`] wrapped in an [Arc].
24#[derive(Debug, Clone)]
25pub struct ParkedPool<T: ParkedOrd> {
26    /// Keeps track of transactions inserted in the pool.
27    ///
28    /// This way we can determine when transactions were submitted to the pool.
29    submission_id: u64,
30    /// _All_ Transactions that are currently inside the pool grouped by their identifier.
31    by_id: BTreeMap<TransactionId, ParkedPoolTransaction<T>>,
32    /// All transactions sorted by their order function.
33    ///
34    /// The higher, the better.
35    best: BTreeSet<ParkedPoolTransaction<T>>,
36    /// Keeps track of last submission id for each sender.
37    ///
38    /// This are sorted in reverse order, so the last (highest) submission id is first, and the
39    /// lowest (oldest) is the last.
40    last_sender_submission: BTreeSet<SubmissionSenderId>,
41    /// Keeps track of the number of transactions in the pool by the sender and the last submission
42    /// id.
43    sender_transaction_count: FxHashMap<SenderId, SenderTransactionCount>,
44    /// Keeps track of the size of this pool.
45    ///
46    /// See also [`reth_primitives_traits::InMemorySize::size`].
47    size_of: SizeTracker,
48}
49
50// === impl ParkedPool ===
51
52impl<T: ParkedOrd> ParkedPool<T> {
53    /// Adds a new transactions to the pending queue.
54    ///
55    /// # Panics
56    ///
57    /// If the transaction is already included.
58    pub fn add_transaction(&mut self, tx: Arc<ValidPoolTransaction<T::Transaction>>) {
59        let id = *tx.id();
60        assert!(
61            !self.contains(&id),
62            "transaction already included {:?}",
63            self.get(&id).unwrap().transaction.transaction
64        );
65        let submission_id = self.next_id();
66
67        // keep track of size
68        self.size_of += tx.size();
69
70        // update or create sender entry
71        self.add_sender_count(tx.sender_id(), submission_id);
72        let transaction = ParkedPoolTransaction { submission_id, transaction: tx.into() };
73
74        self.by_id.insert(id, transaction.clone());
75        self.best.insert(transaction);
76    }
77
78    /// Increments the count of transactions for the given sender and updates the tracked submission
79    /// id.
80    fn add_sender_count(&mut self, sender: SenderId, submission_id: u64) {
81        match self.sender_transaction_count.entry(sender) {
82            Entry::Occupied(mut entry) => {
83                let value = entry.get_mut();
84                // remove the __currently__ tracked submission id
85                self.last_sender_submission
86                    .remove(&SubmissionSenderId::new(sender, value.last_submission_id));
87
88                value.count += 1;
89                value.last_submission_id = submission_id;
90            }
91            Entry::Vacant(entry) => {
92                entry
93                    .insert(SenderTransactionCount { count: 1, last_submission_id: submission_id });
94            }
95        }
96        // insert a new entry
97        self.last_sender_submission.insert(SubmissionSenderId::new(sender, submission_id));
98    }
99
100    /// Decrements the count of transactions for the given sender.
101    ///
102    /// If the count reaches zero, the sender is removed from the map.
103    ///
104    /// Note: this does not update the tracked submission id for the sender, because we're only
105    /// interested in the __last__ submission id when truncating the pool.
106    fn remove_sender_count(&mut self, sender_id: SenderId) {
107        let removed_sender = match self.sender_transaction_count.entry(sender_id) {
108            Entry::Occupied(mut entry) => {
109                let value = entry.get_mut();
110                value.count -= 1;
111                if value.count == 0 {
112                    entry.remove()
113                } else {
114                    return
115                }
116            }
117            Entry::Vacant(_) => {
118                // This should never happen because the bisection between the two maps
119                unreachable!("sender count not found {:?}", sender_id);
120            }
121        };
122
123        // all transactions for this sender have been removed
124        assert!(
125            self.last_sender_submission
126                .remove(&SubmissionSenderId::new(sender_id, removed_sender.last_submission_id)),
127            "last sender transaction not found {sender_id:?}"
128        );
129    }
130
131    /// Returns an iterator over all transactions in the pool
132    pub(crate) fn all(
133        &self,
134    ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
135        self.by_id.values().map(|tx| tx.transaction.clone().into())
136    }
137
138    /// Removes the transaction from the pool
139    pub(crate) fn remove_transaction(
140        &mut self,
141        id: &TransactionId,
142    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
143        // remove from queues
144        let tx = self.by_id.remove(id)?;
145        self.best.remove(&tx);
146        self.remove_sender_count(tx.transaction.sender_id());
147
148        // keep track of size
149        self.size_of -= tx.transaction.size();
150
151        Some(tx.transaction.into())
152    }
153
154    /// Retrieves transactions by sender, using `SmallVec` to efficiently handle up to
155    /// `TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER` transactions.
156    pub(crate) fn get_txs_by_sender(
157        &self,
158        sender: SenderId,
159    ) -> SmallVec<[TransactionId; TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER]> {
160        self.by_id
161            .range((sender.start_bound(), Unbounded))
162            .take_while(move |(other, _)| sender == other.sender)
163            .map(|(tx_id, _)| *tx_id)
164            .collect()
165    }
166
167    #[cfg(test)]
168    pub(crate) fn get_senders_by_submission_id(
169        &self,
170    ) -> impl Iterator<Item = SubmissionSenderId> + '_ {
171        self.last_sender_submission.iter().copied()
172    }
173
174    /// Truncates the pool by removing transactions, until the given [`SubPoolLimit`] has been met.
175    ///
176    /// This is done by first ordering senders by the last time they have submitted a transaction
177    ///
178    /// Uses sender ids sorted by each sender's last submission id. Senders with older last
179    /// submission ids are first. Note that _last_ submission ids are the newest submission id for
180    /// that sender, so this sorts senders by the last time they submitted a transaction in
181    /// descending order. Senders that have least recently submitted a transaction are first.
182    ///
183    /// Then, for each sender, all transactions for that sender are removed, until the pool limits
184    /// have been met.
185    ///
186    /// Any removed transactions are returned.
187    pub fn truncate_pool(
188        &mut self,
189        limit: SubPoolLimit,
190    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
191        if !self.exceeds(&limit) {
192            // if we are below the limits, we don't need to drop anything
193            return Vec::new()
194        }
195
196        let mut removed = Vec::new();
197
198        while limit.is_exceeded(self.len(), self.size()) && !self.last_sender_submission.is_empty()
199        {
200            // NOTE: This will not panic due to `!last_sender_transaction.is_empty()`
201            let sender_id = self.last_sender_submission.last().expect("not empty").sender_id;
202            let list = self.get_txs_by_sender(sender_id);
203
204            // Drop transactions from this sender until the pool is under limits
205            for txid in list.into_iter().rev() {
206                if let Some(tx) = self.remove_transaction(&txid) {
207                    removed.push(tx);
208                }
209
210                if !self.exceeds(&limit) {
211                    break
212                }
213            }
214        }
215
216        removed
217    }
218
219    const fn next_id(&mut self) -> u64 {
220        let id = self.submission_id;
221        self.submission_id = self.submission_id.wrapping_add(1);
222        id
223    }
224
225    /// The reported size of all transactions in this pool.
226    pub(crate) fn size(&self) -> usize {
227        self.size_of.into()
228    }
229
230    /// Number of transactions in the entire pool
231    pub(crate) fn len(&self) -> usize {
232        self.by_id.len()
233    }
234
235    /// Returns true if the pool exceeds the given limit
236    #[inline]
237    pub(crate) fn exceeds(&self, limit: &SubPoolLimit) -> bool {
238        limit.is_exceeded(self.len(), self.size())
239    }
240
241    /// Returns whether the pool is empty
242    #[cfg(test)]
243    pub(crate) fn is_empty(&self) -> bool {
244        self.by_id.is_empty()
245    }
246
247    /// Returns `true` if the transaction with the given id is already included in this pool.
248    pub(crate) fn contains(&self, id: &TransactionId) -> bool {
249        self.by_id.contains_key(id)
250    }
251
252    /// Retrieves a transaction with the given ID from the pool, if it exists.
253    fn get(&self, id: &TransactionId) -> Option<&ParkedPoolTransaction<T>> {
254        self.by_id.get(id)
255    }
256
257    /// Asserts that the bijection between `by_id` and `best` is valid.
258    #[cfg(any(test, feature = "test-utils"))]
259    pub(crate) fn assert_invariants(&self) {
260        assert_eq!(self.by_id.len(), self.best.len(), "by_id.len() != best.len()");
261
262        assert_eq!(
263            self.last_sender_submission.len(),
264            self.sender_transaction_count.len(),
265            "last_sender_transaction.len() != sender_to_last_transaction.len()"
266        );
267    }
268}
269
270impl<T: PoolTransaction> ParkedPool<BasefeeOrd<T>> {
271    /// Returns all transactions that satisfy the given basefee.
272    ///
273    /// Note: this does _not_ remove the transactions
274    pub(crate) fn satisfy_base_fee_transactions(
275        &self,
276        basefee: u64,
277    ) -> Vec<Arc<ValidPoolTransaction<T>>> {
278        let ids = self.satisfy_base_fee_ids(basefee);
279        let mut txs = Vec::with_capacity(ids.len());
280        for id in ids {
281            txs.push(self.get(&id).expect("transaction exists").transaction.clone().into());
282        }
283        txs
284    }
285
286    /// Returns all transactions that satisfy the given basefee.
287    fn satisfy_base_fee_ids(&self, basefee: u64) -> Vec<TransactionId> {
288        let mut transactions = Vec::new();
289        {
290            let mut iter = self.by_id.iter().peekable();
291
292            while let Some((id, tx)) = iter.next() {
293                if tx.transaction.transaction.max_fee_per_gas() < basefee as u128 {
294                    // still parked -> skip descendant transactions
295                    'this: while let Some((peek, _)) = iter.peek() {
296                        if peek.sender != id.sender {
297                            break 'this
298                        }
299                        iter.next();
300                    }
301                } else {
302                    transactions.push(*id);
303                }
304            }
305        }
306        transactions
307    }
308
309    /// Removes all transactions and their dependent transaction from the subpool that no longer
310    /// satisfy the given basefee.
311    ///
312    /// Note: the transactions are not returned in a particular order.
313    pub(crate) fn enforce_basefee(&mut self, basefee: u64) -> Vec<Arc<ValidPoolTransaction<T>>> {
314        let to_remove = self.satisfy_base_fee_ids(basefee);
315
316        let mut removed = Vec::with_capacity(to_remove.len());
317        for id in to_remove {
318            removed.push(self.remove_transaction(&id).expect("transaction exists"));
319        }
320
321        removed
322    }
323}
324
325impl<T: ParkedOrd> Default for ParkedPool<T> {
326    fn default() -> Self {
327        Self {
328            submission_id: 0,
329            by_id: Default::default(),
330            best: Default::default(),
331            last_sender_submission: Default::default(),
332            sender_transaction_count: Default::default(),
333            size_of: Default::default(),
334        }
335    }
336}
337
338/// Keeps track of the number of transactions and the latest submission id for each sender.
339#[derive(Debug, Clone, Default, PartialEq, Eq)]
340struct SenderTransactionCount {
341    count: u64,
342    last_submission_id: u64,
343}
344
345/// Represents a transaction in this pool.
346#[derive(Debug)]
347struct ParkedPoolTransaction<T: ParkedOrd> {
348    /// Identifier that tags when transaction was submitted in the pool.
349    submission_id: u64,
350    /// Actual transaction.
351    transaction: T,
352}
353
354impl<T: ParkedOrd> Clone for ParkedPoolTransaction<T> {
355    fn clone(&self) -> Self {
356        Self { submission_id: self.submission_id, transaction: self.transaction.clone() }
357    }
358}
359
360impl<T: ParkedOrd> Eq for ParkedPoolTransaction<T> {}
361
362impl<T: ParkedOrd> PartialEq<Self> for ParkedPoolTransaction<T> {
363    fn eq(&self, other: &Self) -> bool {
364        self.cmp(other) == Ordering::Equal
365    }
366}
367
368impl<T: ParkedOrd> PartialOrd<Self> for ParkedPoolTransaction<T> {
369    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
370        Some(self.cmp(other))
371    }
372}
373
374impl<T: ParkedOrd> Ord for ParkedPoolTransaction<T> {
375    fn cmp(&self, other: &Self) -> Ordering {
376        // This compares by the transactions first, and only if two tx are equal this compares
377        // the unique `submission_id`.
378        // "better" transactions are Greater
379        self.transaction
380            .cmp(&other.transaction)
381            .then_with(|| other.submission_id.cmp(&self.submission_id))
382    }
383}
384
385/// Includes a [`SenderId`] and `submission_id`. This is used to sort senders by their last
386/// submission id.
387#[derive(Debug, PartialEq, Eq, Copy, Clone)]
388pub(crate) struct SubmissionSenderId {
389    /// The sender id
390    pub(crate) sender_id: SenderId,
391    /// The submission id
392    pub(crate) submission_id: u64,
393}
394
395impl SubmissionSenderId {
396    /// Creates a new [`SubmissionSenderId`] based on the [`SenderId`] and `submission_id`.
397    const fn new(sender_id: SenderId, submission_id: u64) -> Self {
398        Self { sender_id, submission_id }
399    }
400}
401
402impl Ord for SubmissionSenderId {
403    fn cmp(&self, other: &Self) -> Ordering {
404        // Reverse ordering for `submission_id`
405        other.submission_id.cmp(&self.submission_id)
406    }
407}
408
409impl PartialOrd for SubmissionSenderId {
410    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
411        Some(self.cmp(other))
412    }
413}
414
415/// Helper trait used for custom `Ord` wrappers around a transaction.
416///
417/// This is effectively a wrapper for `Arc<ValidPoolTransaction>` with custom `Ord` implementation.
418pub trait ParkedOrd:
419    Ord
420    + Clone
421    + From<Arc<ValidPoolTransaction<Self::Transaction>>>
422    + Into<Arc<ValidPoolTransaction<Self::Transaction>>>
423    + Deref<Target = Arc<ValidPoolTransaction<Self::Transaction>>>
424{
425    /// The wrapper transaction type.
426    type Transaction: PoolTransaction;
427}
428
429/// Helper macro to implement necessary conversions for `ParkedOrd` trait
430macro_rules! impl_ord_wrapper {
431    ($name:ident) => {
432        impl<T: PoolTransaction> Clone for $name<T> {
433            fn clone(&self) -> Self {
434                Self(self.0.clone())
435            }
436        }
437
438        impl<T: PoolTransaction> Eq for $name<T> {}
439
440        impl<T: PoolTransaction> PartialEq<Self> for $name<T> {
441            fn eq(&self, other: &Self) -> bool {
442                self.cmp(other) == Ordering::Equal
443            }
444        }
445
446        impl<T: PoolTransaction> PartialOrd<Self> for $name<T> {
447            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
448                Some(self.cmp(other))
449            }
450        }
451        impl<T: PoolTransaction> Deref for $name<T> {
452            type Target = Arc<ValidPoolTransaction<T>>;
453
454            fn deref(&self) -> &Self::Target {
455                &self.0
456            }
457        }
458
459        impl<T: PoolTransaction> ParkedOrd for $name<T> {
460            type Transaction = T;
461        }
462
463        impl<T: PoolTransaction> From<Arc<ValidPoolTransaction<T>>> for $name<T> {
464            fn from(value: Arc<ValidPoolTransaction<T>>) -> Self {
465                Self(value)
466            }
467        }
468
469        impl<T: PoolTransaction> From<$name<T>> for Arc<ValidPoolTransaction<T>> {
470            fn from(value: $name<T>) -> Arc<ValidPoolTransaction<T>> {
471                value.0
472            }
473        }
474    };
475}
476
477/// A new type wrapper for [`ValidPoolTransaction`]
478///
479/// This sorts transactions by their base fee.
480///
481/// Caution: This assumes all transaction in the `BaseFee` sub-pool have a fee value.
482#[derive(Debug)]
483pub struct BasefeeOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>);
484
485impl_ord_wrapper!(BasefeeOrd);
486
487impl<T: PoolTransaction> Ord for BasefeeOrd<T> {
488    fn cmp(&self, other: &Self) -> Ordering {
489        self.0.transaction.max_fee_per_gas().cmp(&other.0.transaction.max_fee_per_gas())
490    }
491}
492
493/// A new type wrapper for [`ValidPoolTransaction`]
494///
495/// This sorts transactions by their distance.
496///
497/// `Queued` transactions are transactions that are currently blocked by other parked (basefee,
498/// queued) or missing transactions.
499///
500/// The primary order function always compares the transaction costs first. In case these
501/// are equal, it compares the timestamps when the transactions were created.
502#[derive(Debug)]
503pub struct QueuedOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>);
504
505impl_ord_wrapper!(QueuedOrd);
506
507impl<T: PoolTransaction> Ord for QueuedOrd<T> {
508    fn cmp(&self, other: &Self) -> Ordering {
509        // Higher fee is better
510        self.max_fee_per_gas().cmp(&other.max_fee_per_gas()).then_with(||
511            // Lower timestamp is better
512            other.timestamp.cmp(&self.timestamp))
513    }
514}
515
516#[cfg(test)]
517mod tests {
518    use super::*;
519    use crate::test_utils::{MockTransaction, MockTransactionFactory, MockTransactionSet};
520    use alloy_consensus::{Transaction, TxType};
521    use alloy_primitives::address;
522    use std::collections::HashSet;
523
524    #[test]
525    fn test_enforce_parked_basefee() {
526        let mut f = MockTransactionFactory::default();
527        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
528        let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
529        pool.add_transaction(tx.clone());
530
531        assert!(pool.contains(tx.id()));
532        assert_eq!(pool.len(), 1);
533
534        let removed = pool.enforce_basefee(u64::MAX);
535        assert!(removed.is_empty());
536
537        let removed = pool.enforce_basefee((tx.max_fee_per_gas() - 1) as u64);
538        assert_eq!(removed.len(), 1);
539        assert!(pool.is_empty());
540    }
541
542    #[test]
543    fn test_enforce_parked_basefee_descendant() {
544        let mut f = MockTransactionFactory::default();
545        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
546        let t = MockTransaction::eip1559().inc_price_by(10);
547        let root_tx = f.validated_arc(t.clone());
548        pool.add_transaction(root_tx.clone());
549
550        let descendant_tx = f.validated_arc(t.inc_nonce().decr_price());
551        pool.add_transaction(descendant_tx.clone());
552
553        assert!(pool.contains(root_tx.id()));
554        assert!(pool.contains(descendant_tx.id()));
555        assert_eq!(pool.len(), 2);
556
557        let removed = pool.enforce_basefee(u64::MAX);
558        assert!(removed.is_empty());
559        assert_eq!(pool.len(), 2);
560        // two dependent tx in the pool with decreasing fee
561
562        {
563            // TODO: test change might not be intended, re review
564            let mut pool2 = pool.clone();
565            let removed = pool2.enforce_basefee(root_tx.max_fee_per_gas() as u64);
566            assert_eq!(removed.len(), 1);
567            assert_eq!(pool2.len(), 1);
568            // root got popped - descendant should be skipped
569            assert!(!pool2.contains(root_tx.id()));
570            assert!(pool2.contains(descendant_tx.id()));
571        }
572
573        // remove root transaction via descendant tx fee
574        let removed = pool.enforce_basefee(descendant_tx.max_fee_per_gas() as u64);
575        assert_eq!(removed.len(), 2);
576        assert!(pool.is_empty());
577    }
578
579    #[test]
580    fn truncate_parked_by_submission_id() {
581        // this test ensures that we evict from the pending pool by sender
582        let mut f = MockTransactionFactory::default();
583        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
584
585        let a_sender = address!("0x000000000000000000000000000000000000000a");
586        let b_sender = address!("0x000000000000000000000000000000000000000b");
587        let c_sender = address!("0x000000000000000000000000000000000000000c");
588        let d_sender = address!("0x000000000000000000000000000000000000000d");
589
590        // create a chain of transactions by sender A, B, C
591        let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
592        let a = tx_set.clone().into_vec();
593
594        let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
595        tx_set.extend(b.clone());
596
597        // C has the same number of txs as B
598        let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
599        tx_set.extend(c.clone());
600
601        let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
602        tx_set.extend(d.clone());
603
604        let all_txs = tx_set.into_vec();
605
606        // just construct a list of all txs to add
607        let expected_parked = vec![c[0].clone(), c[1].clone(), c[2].clone(), d[0].clone()]
608            .into_iter()
609            .map(|tx| (tx.sender(), tx.nonce()))
610            .collect::<HashSet<_>>();
611
612        // we expect the truncate operation to go through the senders with the most txs, removing
613        // txs based on when they were submitted, removing the oldest txs first, until the pool is
614        // not over the limit
615        let expected_removed = vec![
616            a[0].clone(),
617            a[1].clone(),
618            a[2].clone(),
619            a[3].clone(),
620            b[0].clone(),
621            b[1].clone(),
622            b[2].clone(),
623        ]
624        .into_iter()
625        .map(|tx| (tx.sender(), tx.nonce()))
626        .collect::<HashSet<_>>();
627
628        // add all the transactions to the pool
629        for tx in all_txs {
630            pool.add_transaction(f.validated_arc(tx));
631        }
632
633        // we should end up with the most recently submitted transactions
634        let pool_limit = SubPoolLimit { max_txs: 4, max_size: usize::MAX };
635
636        // truncate the pool
637        let removed = pool.truncate_pool(pool_limit);
638        assert_eq!(removed.len(), expected_removed.len());
639
640        // get the inner txs from the removed txs
641        let removed =
642            removed.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
643        assert_eq!(removed, expected_removed);
644
645        // get the parked pool
646        let parked = pool.all().collect::<Vec<_>>();
647        assert_eq!(parked.len(), expected_parked.len());
648
649        // get the inner txs from the parked txs
650        let parked = parked.into_iter().map(|tx| (tx.sender(), tx.nonce())).collect::<HashSet<_>>();
651        assert_eq!(parked, expected_parked);
652    }
653
654    #[test]
655    fn test_truncate_parked_with_large_tx() {
656        let mut f = MockTransactionFactory::default();
657        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
658        let default_limits = SubPoolLimit::default();
659
660        // create a chain of transactions by sender A
661        // make sure they are all one over half the limit
662        let a_sender = address!("0x000000000000000000000000000000000000000a");
663
664        // 2 txs, that should put the pool over the size limit but not max txs
665        let a_txs = MockTransactionSet::dependent(a_sender, 0, 2, TxType::Eip1559)
666            .into_iter()
667            .map(|mut tx| {
668                tx.set_size(default_limits.max_size / 2 + 1);
669                tx
670            })
671            .collect::<Vec<_>>();
672
673        // add all the transactions to the pool
674        for tx in a_txs {
675            pool.add_transaction(f.validated_arc(tx));
676        }
677
678        // truncate the pool, it should remove at least one transaction
679        let removed = pool.truncate_pool(default_limits);
680        assert_eq!(removed.len(), 1);
681    }
682
683    #[test]
684    fn test_senders_by_submission_id() {
685        // this test ensures that we evict from the pending pool by sender
686        let mut f = MockTransactionFactory::default();
687        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
688
689        let a_sender = address!("0x000000000000000000000000000000000000000a");
690        let b_sender = address!("0x000000000000000000000000000000000000000b");
691        let c_sender = address!("0x000000000000000000000000000000000000000c");
692        let d_sender = address!("0x000000000000000000000000000000000000000d");
693
694        // create a chain of transactions by sender A, B, C
695        let mut tx_set = MockTransactionSet::dependent(a_sender, 0, 4, TxType::Eip1559);
696        let a = tx_set.clone().into_vec();
697
698        let b = MockTransactionSet::dependent(b_sender, 0, 3, TxType::Eip1559).into_vec();
699        tx_set.extend(b.clone());
700
701        // C has the same number of txs as B
702        let c = MockTransactionSet::dependent(c_sender, 0, 3, TxType::Eip1559).into_vec();
703        tx_set.extend(c.clone());
704
705        let d = MockTransactionSet::dependent(d_sender, 0, 1, TxType::Eip1559).into_vec();
706        tx_set.extend(d.clone());
707
708        let all_txs = tx_set.into_vec();
709
710        // add all the transactions to the pool
711        for tx in all_txs {
712            pool.add_transaction(f.validated_arc(tx));
713        }
714
715        // get senders by submission id - a4, b3, c3, d1, reversed
716        let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
717        assert_eq!(senders.len(), 4);
718        let expected_senders = vec![d_sender, c_sender, b_sender, a_sender]
719            .into_iter()
720            .map(|s| f.ids.sender_id(&s).unwrap())
721            .collect::<Vec<_>>();
722        assert_eq!(senders, expected_senders);
723
724        // manually order the txs
725        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
726        let all_txs = vec![d[0].clone(), b[0].clone(), c[0].clone(), a[0].clone()];
727
728        // add all the transactions to the pool
729        for tx in all_txs {
730            pool.add_transaction(f.validated_arc(tx));
731        }
732
733        let senders = pool.get_senders_by_submission_id().map(|s| s.sender_id).collect::<Vec<_>>();
734        assert_eq!(senders.len(), 4);
735        let expected_senders = vec![a_sender, c_sender, b_sender, d_sender]
736            .into_iter()
737            .map(|s| f.ids.sender_id(&s).unwrap())
738            .collect::<Vec<_>>();
739        assert_eq!(senders, expected_senders);
740    }
741
742    #[test]
743    fn test_add_sender_count_new_sender() {
744        // Initialize a mock transaction factory
745        let mut f = MockTransactionFactory::default();
746        // Create an empty transaction pool
747        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
748        // Generate a validated transaction and add it to the pool
749        let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
750        pool.add_transaction(tx);
751
752        // Define a new sender ID and submission ID
753        let sender: SenderId = 11.into();
754        let submission_id = 1;
755
756        // Add the sender count to the pool
757        pool.add_sender_count(sender, submission_id);
758
759        // Assert that the sender transaction count is updated correctly
760        assert_eq!(pool.sender_transaction_count.len(), 2);
761        let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
762        assert_eq!(sender_info.count, 1);
763        assert_eq!(sender_info.last_submission_id, submission_id);
764
765        // Assert that the last sender submission is updated correctly
766        assert_eq!(pool.last_sender_submission.len(), 2);
767        let submission_info = pool.last_sender_submission.iter().next().unwrap();
768        assert_eq!(submission_info.sender_id, sender);
769        assert_eq!(submission_info.submission_id, submission_id);
770    }
771
772    #[test]
773    fn test_add_sender_count_existing_sender() {
774        // Initialize a mock transaction factory
775        let mut f = MockTransactionFactory::default();
776        // Create an empty transaction pool
777        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
778        // Generate a validated transaction and add it to the pool
779        let tx = f.validated_arc(MockTransaction::eip1559().inc_price());
780        pool.add_transaction(tx);
781
782        // Define a sender ID and initial submission ID
783        let sender: SenderId = 11.into();
784        let initial_submission_id = 1;
785
786        // Add the sender count to the pool with the initial submission ID
787        pool.add_sender_count(sender, initial_submission_id);
788
789        // Define a new submission ID
790        let new_submission_id = 2;
791        // Add the sender count to the pool with the new submission ID
792        pool.add_sender_count(sender, new_submission_id);
793
794        // Assert that the sender transaction count is updated correctly
795        assert_eq!(pool.sender_transaction_count.len(), 2);
796        let sender_info = pool.sender_transaction_count.get(&sender).unwrap();
797        assert_eq!(sender_info.count, 2);
798        assert_eq!(sender_info.last_submission_id, new_submission_id);
799
800        // Assert that the last sender submission is updated correctly
801        assert_eq!(pool.last_sender_submission.len(), 2);
802        let submission_info = pool.last_sender_submission.iter().next().unwrap();
803        assert_eq!(submission_info.sender_id, sender);
804        assert_eq!(submission_info.submission_id, new_submission_id);
805    }
806
807    #[test]
808    fn test_add_sender_count_multiple_senders() {
809        // Initialize a mock transaction factory
810        let mut f = MockTransactionFactory::default();
811        // Create an empty transaction pool
812        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
813        // Generate two validated transactions and add them to the pool
814        let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
815        let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
816        pool.add_transaction(tx1);
817        pool.add_transaction(tx2);
818
819        // Define two different sender IDs and their corresponding submission IDs
820        let sender1: SenderId = 11.into();
821        let sender2: SenderId = 22.into();
822
823        // Add the sender counts to the pool
824        pool.add_sender_count(sender1, 1);
825        pool.add_sender_count(sender2, 2);
826
827        // Assert that the sender transaction counts are updated correctly
828        assert_eq!(pool.sender_transaction_count.len(), 4);
829
830        let sender1_info = pool.sender_transaction_count.get(&sender1).unwrap();
831        assert_eq!(sender1_info.count, 1);
832        assert_eq!(sender1_info.last_submission_id, 1);
833
834        let sender2_info = pool.sender_transaction_count.get(&sender2).unwrap();
835        assert_eq!(sender2_info.count, 1);
836        assert_eq!(sender2_info.last_submission_id, 2);
837
838        // Assert that the last sender submission is updated correctly
839        assert_eq!(pool.last_sender_submission.len(), 3);
840
841        // Verify that sender 1 is not in the last sender submission
842        let submission_info1 =
843            pool.last_sender_submission.iter().find(|info| info.sender_id == sender1);
844        assert!(submission_info1.is_none());
845
846        // Verify that sender 2 is in the last sender submission
847        let submission_info2 =
848            pool.last_sender_submission.iter().find(|info| info.sender_id == sender2).unwrap();
849        assert_eq!(submission_info2.sender_id, sender2);
850        assert_eq!(submission_info2.submission_id, 2);
851    }
852
853    #[test]
854    fn test_remove_sender_count() {
855        // Initialize a mock transaction factory
856        let mut f = MockTransactionFactory::default();
857        // Create an empty transaction pool
858        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
859        // Generate two validated transactions and add them to the pool
860        let tx1 = f.validated_arc(MockTransaction::eip1559().inc_price());
861        let tx2 = f.validated_arc(MockTransaction::eip1559().inc_price());
862        pool.add_transaction(tx1);
863        pool.add_transaction(tx2);
864
865        // Define two different sender IDs and their corresponding submission IDs
866        let sender1: SenderId = 11.into();
867        let sender2: SenderId = 22.into();
868
869        // Add the sender counts to the pool
870        pool.add_sender_count(sender1, 1);
871
872        // We add sender 2 multiple times to test the removal of sender counts
873        pool.add_sender_count(sender2, 2);
874        pool.add_sender_count(sender2, 3);
875
876        // Before removing the sender count we should have 4 sender transaction counts
877        assert_eq!(pool.sender_transaction_count.len(), 4);
878        assert!(pool.sender_transaction_count.contains_key(&sender1));
879
880        // We should have 1 sender transaction count for sender 1 before removing the sender count
881        assert_eq!(pool.sender_transaction_count.get(&sender1).unwrap().count, 1);
882
883        // Remove the sender count for sender 1
884        pool.remove_sender_count(sender1);
885
886        // After removing the sender count we should have 3 sender transaction counts remaining
887        assert_eq!(pool.sender_transaction_count.len(), 3);
888        assert!(!pool.sender_transaction_count.contains_key(&sender1));
889
890        // Check the sender transaction count for sender 2 before removing the sender count
891        assert_eq!(
892            *pool.sender_transaction_count.get(&sender2).unwrap(),
893            SenderTransactionCount { count: 2, last_submission_id: 3 }
894        );
895
896        // Remove the sender count for sender 2
897        pool.remove_sender_count(sender2);
898
899        // After removing the sender count for sender 2, we still have 3 sender transaction counts
900        // remaining.
901        //
902        // This is because we added sender 2 multiple times and we only removed the last submission.
903        assert_eq!(pool.sender_transaction_count.len(), 3);
904        assert!(pool.sender_transaction_count.contains_key(&sender2));
905
906        // Sender transaction count for sender 2 should be updated correctly
907        assert_eq!(
908            *pool.sender_transaction_count.get(&sender2).unwrap(),
909            SenderTransactionCount { count: 1, last_submission_id: 3 }
910        );
911    }
912
913    #[test]
914    fn test_pool_size() {
915        let mut f = MockTransactionFactory::default();
916        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
917
918        // Create a transaction with a specific size and add it to the pool
919        let tx = f.validated_arc(MockTransaction::eip1559().set_size(1024).clone());
920        pool.add_transaction(tx);
921
922        // Assert that the reported size of the pool is correct
923        assert_eq!(pool.size(), 1024);
924    }
925
926    #[test]
927    fn test_pool_len() {
928        let mut f = MockTransactionFactory::default();
929        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
930
931        // Initially, the pool should have zero transactions
932        assert_eq!(pool.len(), 0);
933
934        // Add a transaction to the pool and check the length
935        let tx = f.validated_arc(MockTransaction::eip1559());
936        pool.add_transaction(tx);
937        assert_eq!(pool.len(), 1);
938    }
939
940    #[test]
941    fn test_pool_contains() {
942        let mut f = MockTransactionFactory::default();
943        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
944
945        // Create a transaction and get its ID
946        let tx = f.validated_arc(MockTransaction::eip1559());
947        let tx_id = *tx.id();
948
949        // Before adding, the transaction should not be in the pool
950        assert!(!pool.contains(&tx_id));
951
952        // After adding, the transaction should be present in the pool
953        pool.add_transaction(tx);
954        assert!(pool.contains(&tx_id));
955    }
956
957    #[test]
958    fn test_get_transaction() {
959        let mut f = MockTransactionFactory::default();
960        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
961
962        // Add a transaction to the pool and get its ID
963        let tx = f.validated_arc(MockTransaction::eip1559());
964        let tx_id = *tx.id();
965        pool.add_transaction(tx.clone());
966
967        // Retrieve the transaction using `get()` and assert it matches the added transaction
968        let retrieved = pool.get(&tx_id).expect("Transaction should exist in the pool");
969        assert_eq!(retrieved.transaction.id(), tx.id());
970    }
971
972    #[test]
973    fn test_all_transactions() {
974        let mut f = MockTransactionFactory::default();
975        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
976
977        // Add two transactions to the pool
978        let tx1 = f.validated_arc(MockTransaction::eip1559());
979        let tx2 = f.validated_arc(MockTransaction::eip1559());
980        pool.add_transaction(tx1.clone());
981        pool.add_transaction(tx2.clone());
982
983        // Collect all transaction IDs from the pool
984        let all_txs: Vec<_> = pool.all().map(|tx| *tx.id()).collect();
985        assert_eq!(all_txs.len(), 2);
986
987        // Check that the IDs of both transactions are present
988        assert!(all_txs.contains(tx1.id()));
989        assert!(all_txs.contains(tx2.id()));
990    }
991
992    #[test]
993    fn test_truncate_pool_edge_case() {
994        let mut f = MockTransactionFactory::default();
995        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
996
997        // Add two transactions to the pool
998        let tx1 = f.validated_arc(MockTransaction::eip1559());
999        let tx2 = f.validated_arc(MockTransaction::eip1559());
1000        pool.add_transaction(tx1);
1001        pool.add_transaction(tx2);
1002
1003        // Set a limit that matches the current number of transactions
1004        let limit = SubPoolLimit { max_txs: 2, max_size: usize::MAX };
1005        let removed = pool.truncate_pool(limit);
1006
1007        // No transactions should be removed
1008        assert!(removed.is_empty());
1009
1010        // Set a stricter limit that requires truncating one transaction
1011        let limit = SubPoolLimit { max_txs: 1, max_size: usize::MAX };
1012        let removed = pool.truncate_pool(limit);
1013
1014        // One transaction should be removed, and the pool should have one left
1015        assert_eq!(removed.len(), 1);
1016        assert_eq!(pool.len(), 1);
1017    }
1018
1019    #[test]
1020    fn test_satisfy_base_fee_transactions() {
1021        let mut f = MockTransactionFactory::default();
1022        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1023
1024        // Add two transactions with different max fees
1025        let tx1 = f.validated_arc(MockTransaction::eip1559().set_max_fee(100).clone());
1026        let tx2 = f.validated_arc(MockTransaction::eip1559().set_max_fee(200).clone());
1027        pool.add_transaction(tx1);
1028        pool.add_transaction(tx2.clone());
1029
1030        // Check that only the second transaction satisfies the base fee requirement
1031        let satisfied = pool.satisfy_base_fee_transactions(150);
1032        assert_eq!(satisfied.len(), 1);
1033        assert_eq!(satisfied[0].id(), tx2.id())
1034    }
1035
1036    #[test]
1037    fn test_remove_transaction() {
1038        let mut f = MockTransactionFactory::default();
1039        let mut pool = ParkedPool::<BasefeeOrd<_>>::default();
1040
1041        // Add a transaction to the pool and get its ID
1042        let tx = f.validated_arc(MockTransaction::eip1559());
1043        let tx_id = *tx.id();
1044        pool.add_transaction(tx);
1045
1046        // Ensure the transaction is in the pool before removal
1047        assert!(pool.contains(&tx_id));
1048
1049        // Remove the transaction and check that it is no longer in the pool
1050        let removed = pool.remove_transaction(&tx_id);
1051        assert!(removed.is_some());
1052        assert!(!pool.contains(&tx_id));
1053    }
1054
1055    #[test]
1056    fn test_parkpool_ord() {
1057        let mut f = MockTransactionFactory::default();
1058        let mut pool = ParkedPool::<QueuedOrd<_>>::default();
1059
1060        let tx1 = MockTransaction::eip1559().with_max_fee(100);
1061        let tx1_v = f.validated_arc(tx1.clone());
1062
1063        let tx2 = MockTransaction::eip1559().with_max_fee(101);
1064        let tx2_v = f.validated_arc(tx2.clone());
1065
1066        let tx3 = MockTransaction::eip1559().with_max_fee(101);
1067        let tx3_v = f.validated_arc(tx3.clone());
1068
1069        let tx4 = MockTransaction::eip1559().with_max_fee(101);
1070        let mut tx4_v = f.validated(tx4.clone());
1071        tx4_v.timestamp = tx3_v.timestamp;
1072
1073        let ord_1 = QueuedOrd(tx1_v.clone());
1074        let ord_2 = QueuedOrd(tx2_v.clone());
1075        let ord_3 = QueuedOrd(tx3_v.clone());
1076        assert!(ord_1 < ord_2);
1077        // lower timestamp is better
1078        assert!(ord_2 > ord_3);
1079        assert!(ord_1 < ord_3);
1080
1081        pool.add_transaction(tx1_v);
1082        pool.add_transaction(tx2_v);
1083        pool.add_transaction(tx3_v);
1084        pool.add_transaction(Arc::new(tx4_v));
1085
1086        // from worst to best
1087        let mut iter = pool.best.iter();
1088        let tx = iter.next().unwrap();
1089        assert_eq!(tx.transaction.transaction, tx1);
1090
1091        let tx = iter.next().unwrap();
1092        assert_eq!(tx.transaction.transaction, tx4);
1093
1094        let tx = iter.next().unwrap();
1095        assert_eq!(tx.transaction.transaction, tx3);
1096
1097        let tx = iter.next().unwrap();
1098        assert_eq!(tx.transaction.transaction, tx2);
1099    }
1100}