reth_transaction_pool/pool/
txpool.rs

1//! The internal transaction pool implementation.
2
3use crate::{
4    config::{LocalTransactionConfig, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER},
5    error::{Eip4844PoolTransactionError, InvalidPoolTransactionError, PoolError, PoolErrorKind},
6    identifier::{SenderId, TransactionId},
7    metrics::{AllTransactionsMetrics, TxPoolMetrics},
8    pool::{
9        best::BestTransactions,
10        blob::BlobTransactions,
11        parked::{BasefeeOrd, ParkedPool, QueuedOrd},
12        pending::PendingPool,
13        state::{SubPool, TxState},
14        update::{Destination, PoolUpdate},
15        AddedPendingTransaction, AddedTransaction, OnNewCanonicalStateOutcome,
16    },
17    traits::{BestTransactionsAttributes, BlockInfo, PoolSize},
18    PoolConfig, PoolResult, PoolTransaction, PoolUpdateKind, PriceBumpConfig, TransactionOrdering,
19    ValidPoolTransaction, U256,
20};
21use alloy_consensus::constants::{
22    EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID,
23    LEGACY_TX_TYPE_ID,
24};
25use alloy_eips::{
26    eip1559::{ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE},
27    eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
28};
29use alloy_primitives::{Address, TxHash, B256};
30use rustc_hash::FxHashMap;
31use smallvec::SmallVec;
32use std::{
33    cmp::Ordering,
34    collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet},
35    fmt,
36    ops::Bound::{Excluded, Unbounded},
37    sync::Arc,
38};
39use tracing::trace;
40
41#[cfg_attr(doc, aquamarine::aquamarine)]
42// TODO: Inlined diagram due to a bug in aquamarine library, should become an include when it's
43// fixed. See https://github.com/mersinvald/aquamarine/issues/50
44// include_mmd!("docs/mermaid/txpool.mmd")
45/// A pool that manages transactions.
46///
47/// This pool maintains the state of all transactions and stores them accordingly.
48///
49/// ```mermaid
50/// graph TB
51///   subgraph TxPool
52///     direction TB
53///     pool[(All Transactions)]
54///     subgraph Subpools
55///         direction TB
56///         B3[(Queued)]
57///         B1[(Pending)]
58///         B2[(Basefee)]
59///         B4[(Blob)]
60///     end
61///   end
62///   discard([discard])
63///   production([Block Production])
64///   new([New Block])
65///   A[Incoming Tx] --> B[Validation] -->|ins
66///   pool --> |if ready + blobfee too low| B4
67///   pool --> |if ready| B1
68///   pool --> |if ready + basfee too low| B2
69///   pool --> |nonce gap or lack of funds| B3
70///   pool --> |update| pool
71///   B1 --> |best| production
72///   B2 --> |worst| discard
73///   B3 --> |worst| discard
74///   B4 --> |worst| discard
75///   B1 --> |increased blob fee| B4
76///   B4 --> |decreased blob fee| B1
77///   B1 --> |increased base fee| B2
78///   B2 --> |decreased base fee| B1
79///   B3 --> |promote| B1
80///   B3 --> |promote| B2
81///   new --> |apply state changes| pool
82/// ```
83pub struct TxPool<T: TransactionOrdering> {
84    /// Contains the currently known information about the senders.
85    sender_info: FxHashMap<SenderId, SenderInfo>,
86    /// pending subpool
87    ///
88    /// Holds transactions that are ready to be executed on the current state.
89    pending_pool: PendingPool<T>,
90    /// Pool settings to enforce limits etc.
91    config: PoolConfig,
92    /// queued subpool
93    ///
94    /// Holds all parked transactions that depend on external changes from the sender:
95    ///
96    ///    - blocked by missing ancestor transaction (has nonce gaps)
97    ///    - sender lacks funds to pay for this transaction.
98    queued_pool: ParkedPool<QueuedOrd<T::Transaction>>,
99    /// base fee subpool
100    ///
101    /// Holds all parked transactions that currently violate the dynamic fee requirement but could
102    /// be moved to pending if the base fee changes in their favor (decreases) in future blocks.
103    basefee_pool: ParkedPool<BasefeeOrd<T::Transaction>>,
104    /// Blob transactions in the pool that are __not pending__.
105    ///
106    /// This means they either do not satisfy the dynamic fee requirement or the blob fee
107    /// requirement. These transactions can be moved to pending if the base fee or blob fee changes
108    /// in their favor (decreases) in future blocks. The transaction may need both the base fee and
109    /// blob fee to decrease to become executable.
110    blob_pool: BlobTransactions<T::Transaction>,
111    /// All transactions in the pool.
112    all_transactions: AllTransactions<T::Transaction>,
113    /// Transaction pool metrics
114    metrics: TxPoolMetrics,
115    /// The last update kind that was applied to the pool.
116    latest_update_kind: Option<PoolUpdateKind>,
117}
118
119// === impl TxPool ===
120
121impl<T: TransactionOrdering> TxPool<T> {
122    /// Create a new graph pool instance.
123    pub fn new(ordering: T, config: PoolConfig) -> Self {
124        Self {
125            sender_info: Default::default(),
126            pending_pool: PendingPool::new(ordering),
127            queued_pool: Default::default(),
128            basefee_pool: Default::default(),
129            blob_pool: Default::default(),
130            all_transactions: AllTransactions::new(&config),
131            config,
132            metrics: Default::default(),
133            latest_update_kind: None,
134        }
135    }
136
137    /// Retrieves the highest nonce for a specific sender from the transaction pool.
138    pub fn get_highest_nonce_by_sender(&self, sender: SenderId) -> Option<u64> {
139        self.all().txs_iter(sender).last().map(|(_, tx)| tx.transaction.nonce())
140    }
141
142    /// Retrieves the highest transaction (wrapped in an `Arc`) for a specific sender from the
143    /// transaction pool.
144    pub fn get_highest_transaction_by_sender(
145        &self,
146        sender: SenderId,
147    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
148        self.all().txs_iter(sender).last().map(|(_, tx)| Arc::clone(&tx.transaction))
149    }
150
151    /// Returns the transaction with the highest nonce that is executable given the on chain nonce.
152    ///
153    /// If the pool already tracks a higher nonce for the given sender, then this nonce is used
154    /// instead.
155    ///
156    /// Note: The next pending pooled transaction must have the on chain nonce.
157    pub(crate) fn get_highest_consecutive_transaction_by_sender(
158        &self,
159        mut on_chain: TransactionId,
160    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
161        let mut last_consecutive_tx = None;
162
163        // ensure this operates on the most recent
164        if let Some(current) = self.sender_info.get(&on_chain.sender) {
165            on_chain.nonce = on_chain.nonce.max(current.state_nonce);
166        }
167
168        let mut next_expected_nonce = on_chain.nonce;
169        for (id, tx) in self.all().descendant_txs_inclusive(&on_chain) {
170            if next_expected_nonce != id.nonce {
171                break
172            }
173            next_expected_nonce = id.next_nonce();
174            last_consecutive_tx = Some(tx);
175        }
176
177        last_consecutive_tx.map(|tx| Arc::clone(&tx.transaction))
178    }
179
180    /// Returns access to the [`AllTransactions`] container.
181    pub(crate) const fn all(&self) -> &AllTransactions<T::Transaction> {
182        &self.all_transactions
183    }
184
185    /// Returns all senders in the pool
186    pub(crate) fn unique_senders(&self) -> HashSet<Address> {
187        self.all_transactions.txs.values().map(|tx| tx.transaction.sender()).collect()
188    }
189
190    /// Returns stats about the size of pool.
191    pub fn size(&self) -> PoolSize {
192        PoolSize {
193            pending: self.pending_pool.len(),
194            pending_size: self.pending_pool.size(),
195            basefee: self.basefee_pool.len(),
196            basefee_size: self.basefee_pool.size(),
197            queued: self.queued_pool.len(),
198            queued_size: self.queued_pool.size(),
199            blob: self.blob_pool.len(),
200            blob_size: self.blob_pool.size(),
201            total: self.all_transactions.len(),
202        }
203    }
204
205    /// Returns the currently tracked block values
206    pub const fn block_info(&self) -> BlockInfo {
207        BlockInfo {
208            block_gas_limit: self.all_transactions.block_gas_limit,
209            last_seen_block_hash: self.all_transactions.last_seen_block_hash,
210            last_seen_block_number: self.all_transactions.last_seen_block_number,
211            pending_basefee: self.all_transactions.pending_fees.base_fee,
212            pending_blob_fee: Some(self.all_transactions.pending_fees.blob_fee),
213        }
214    }
215
216    /// Updates the tracked blob fee
217    fn update_blob_fee(&mut self, mut pending_blob_fee: u128, base_fee_update: Ordering) {
218        std::mem::swap(&mut self.all_transactions.pending_fees.blob_fee, &mut pending_blob_fee);
219        match (self.all_transactions.pending_fees.blob_fee.cmp(&pending_blob_fee), base_fee_update)
220        {
221            (Ordering::Equal, Ordering::Equal | Ordering::Greater) => {
222                // fee unchanged, nothing to update
223            }
224            (Ordering::Greater, Ordering::Equal | Ordering::Greater) => {
225                // increased blob fee: recheck pending pool and remove all that are no longer valid
226                let removed =
227                    self.pending_pool.update_blob_fee(self.all_transactions.pending_fees.blob_fee);
228                for tx in removed {
229                    let to = {
230                        let tx =
231                            self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
232
233                        // the blob fee is too high now, unset the blob fee cap block flag
234                        tx.state.remove(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
235                        tx.subpool = tx.state.into();
236                        tx.subpool
237                    };
238                    self.add_transaction_to_subpool(to, tx);
239                }
240            }
241            (Ordering::Less, _) | (_, Ordering::Less) => {
242                // decreased blob/base fee: recheck blob pool and promote all that are now valid
243                let removed =
244                    self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees);
245                for tx in removed {
246                    let to = {
247                        let tx =
248                            self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
249                        tx.state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
250                        tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
251                        tx.subpool = tx.state.into();
252                        tx.subpool
253                    };
254                    self.add_transaction_to_subpool(to, tx);
255                }
256            }
257        }
258    }
259
260    /// Updates the tracked basefee
261    ///
262    /// Depending on the change in direction of the basefee, this will promote or demote
263    /// transactions from the basefee pool.
264    fn update_basefee(&mut self, mut pending_basefee: u64) -> Ordering {
265        std::mem::swap(&mut self.all_transactions.pending_fees.base_fee, &mut pending_basefee);
266        match self.all_transactions.pending_fees.base_fee.cmp(&pending_basefee) {
267            Ordering::Equal => {
268                // fee unchanged, nothing to update
269                Ordering::Equal
270            }
271            Ordering::Greater => {
272                // increased base fee: recheck pending pool and remove all that are no longer valid
273                let removed =
274                    self.pending_pool.update_base_fee(self.all_transactions.pending_fees.base_fee);
275                for tx in removed {
276                    let to = {
277                        let tx =
278                            self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
279                        tx.state.remove(TxState::ENOUGH_FEE_CAP_BLOCK);
280                        tx.subpool = tx.state.into();
281                        tx.subpool
282                    };
283                    self.add_transaction_to_subpool(to, tx);
284                }
285
286                Ordering::Greater
287            }
288            Ordering::Less => {
289                // decreased base fee: recheck basefee pool and promote all that are now valid
290                let removed =
291                    self.basefee_pool.enforce_basefee(self.all_transactions.pending_fees.base_fee);
292                for tx in removed {
293                    let to = {
294                        let tx =
295                            self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
296                        tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
297                        tx.subpool = tx.state.into();
298                        tx.subpool
299                    };
300                    self.add_transaction_to_subpool(to, tx);
301                }
302
303                Ordering::Less
304            }
305        }
306    }
307
308    /// Sets the current block info for the pool.
309    ///
310    /// This will also apply updates to the pool based on the new base fee
311    pub fn set_block_info(&mut self, info: BlockInfo) {
312        let BlockInfo {
313            block_gas_limit,
314            last_seen_block_hash,
315            last_seen_block_number,
316            pending_basefee,
317            pending_blob_fee,
318        } = info;
319        self.all_transactions.last_seen_block_hash = last_seen_block_hash;
320        self.all_transactions.last_seen_block_number = last_seen_block_number;
321        let basefee_ordering = self.update_basefee(pending_basefee);
322
323        self.all_transactions.block_gas_limit = block_gas_limit;
324
325        if let Some(blob_fee) = pending_blob_fee {
326            self.update_blob_fee(blob_fee, basefee_ordering)
327        }
328    }
329
330    /// Returns an iterator that yields transactions that are ready to be included in the block with
331    /// the tracked fees.
332    pub(crate) fn best_transactions(&self) -> BestTransactions<T> {
333        self.pending_pool.best()
334    }
335
336    /// Returns an iterator that yields transactions that are ready to be included in the block with
337    /// the given base fee and optional blob fee.
338    ///
339    /// If the provided attributes differ from the currently tracked fees, this will also include
340    /// transactions that are unlocked by the new fees, or exclude transactions that are no longer
341    /// valid with the new fees.
342    pub(crate) fn best_transactions_with_attributes(
343        &self,
344        best_transactions_attributes: BestTransactionsAttributes,
345    ) -> Box<dyn crate::traits::BestTransactions<Item = Arc<ValidPoolTransaction<T::Transaction>>>>
346    {
347        // First we need to check if the given base fee is different than what's currently being
348        // tracked
349        match best_transactions_attributes.basefee.cmp(&self.all_transactions.pending_fees.base_fee)
350        {
351            Ordering::Equal => {
352                // for EIP-4844 transactions we also need to check if the blob fee is now lower than
353                // what's currently being tracked, if so we need to include transactions from the
354                // blob pool that are valid with the lower blob fee
355                if best_transactions_attributes
356                    .blob_fee
357                    .is_some_and(|fee| fee < self.all_transactions.pending_fees.blob_fee as u64)
358                {
359                    let unlocked_by_blob_fee =
360                        self.blob_pool.satisfy_attributes(best_transactions_attributes);
361
362                    Box::new(self.pending_pool.best_with_unlocked(
363                        unlocked_by_blob_fee,
364                        self.all_transactions.pending_fees.base_fee,
365                    ))
366                } else {
367                    Box::new(self.pending_pool.best())
368                }
369            }
370            Ordering::Greater => {
371                // base fee increased, we only need to enforce this on the pending pool
372                Box::new(self.pending_pool.best_with_basefee_and_blobfee(
373                    best_transactions_attributes.basefee,
374                    best_transactions_attributes.blob_fee.unwrap_or_default(),
375                ))
376            }
377            Ordering::Less => {
378                // base fee decreased, we need to move transactions from the basefee + blob pool to
379                // the pending pool that might be unlocked by the lower base fee
380                let mut unlocked = self
381                    .basefee_pool
382                    .satisfy_base_fee_transactions(best_transactions_attributes.basefee);
383
384                // also include blob pool transactions that are now unlocked
385                unlocked.extend(self.blob_pool.satisfy_attributes(best_transactions_attributes));
386
387                Box::new(
388                    self.pending_pool
389                        .best_with_unlocked(unlocked, self.all_transactions.pending_fees.base_fee),
390                )
391            }
392        }
393    }
394
395    /// Returns all transactions from the pending sub-pool
396    pub(crate) fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
397        self.pending_pool.all().collect()
398    }
399    /// Returns an iterator over all transactions from the pending sub-pool
400    pub(crate) fn pending_transactions_iter(
401        &self,
402    ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
403        self.pending_pool.all()
404    }
405
406    /// Returns all pending transactions filtered by predicate
407    pub(crate) fn pending_transactions_with_predicate(
408        &self,
409        mut predicate: impl FnMut(&ValidPoolTransaction<T::Transaction>) -> bool,
410    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
411        self.pending_transactions_iter().filter(|tx| predicate(tx)).collect()
412    }
413
414    /// Returns all pending transactions for the specified sender
415    pub(crate) fn pending_txs_by_sender(
416        &self,
417        sender: SenderId,
418    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
419        self.pending_transactions_iter().filter(|tx| tx.sender_id() == sender).collect()
420    }
421
422    /// Returns all transactions from parked pools
423    pub(crate) fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
424        self.basefee_pool.all().chain(self.queued_pool.all()).collect()
425    }
426
427    /// Returns an iterator over all transactions from parked pools
428    pub(crate) fn queued_transactions_iter(
429        &self,
430    ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
431        self.basefee_pool.all().chain(self.queued_pool.all())
432    }
433
434    /// Returns queued and pending transactions for the specified sender
435    pub fn queued_and_pending_txs_by_sender(
436        &self,
437        sender: SenderId,
438    ) -> (SmallVec<[TransactionId; TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER]>, Vec<TransactionId>) {
439        (self.queued_pool.get_txs_by_sender(sender), self.pending_pool.get_txs_by_sender(sender))
440    }
441
442    /// Returns all queued transactions for the specified sender
443    pub(crate) fn queued_txs_by_sender(
444        &self,
445        sender: SenderId,
446    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
447        self.queued_transactions_iter().filter(|tx| tx.sender_id() == sender).collect()
448    }
449
450    /// Returns `true` if the transaction with the given hash is already included in this pool.
451    pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
452        self.all_transactions.contains(tx_hash)
453    }
454
455    /// Returns `true` if the transaction with the given id is already included in the given subpool
456    #[cfg(test)]
457    pub(crate) fn subpool_contains(&self, subpool: SubPool, id: &TransactionId) -> bool {
458        match subpool {
459            SubPool::Queued => self.queued_pool.contains(id),
460            SubPool::Pending => self.pending_pool.contains(id),
461            SubPool::BaseFee => self.basefee_pool.contains(id),
462            SubPool::Blob => self.blob_pool.contains(id),
463        }
464    }
465
466    /// Returns `true` if the pool is over its configured limits.
467    #[inline]
468    pub(crate) fn is_exceeded(&self) -> bool {
469        self.config.is_exceeded(self.size())
470    }
471
472    /// Returns the transaction for the given hash.
473    pub(crate) fn get(
474        &self,
475        tx_hash: &TxHash,
476    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
477        self.all_transactions.by_hash.get(tx_hash).cloned()
478    }
479
480    /// Returns transactions for the multiple given hashes, if they exist.
481    pub(crate) fn get_all(
482        &self,
483        txs: Vec<TxHash>,
484    ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
485        txs.into_iter().filter_map(|tx| self.get(&tx))
486    }
487
488    /// Returns all transactions sent from the given sender.
489    pub(crate) fn get_transactions_by_sender(
490        &self,
491        sender: SenderId,
492    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
493        self.all_transactions.txs_iter(sender).map(|(_, tx)| Arc::clone(&tx.transaction)).collect()
494    }
495
496    /// Updates the transactions for the changed senders.
497    pub(crate) fn update_accounts(
498        &mut self,
499        changed_senders: FxHashMap<SenderId, SenderInfo>,
500    ) -> UpdateOutcome<T::Transaction> {
501        // Apply the state changes to the total set of transactions which triggers sub-pool updates.
502        let updates = self.all_transactions.update(&changed_senders);
503
504        // track changed accounts
505        self.sender_info.extend(changed_senders);
506
507        // Process the sub-pool updates
508        let update = self.process_updates(updates);
509        // update the metrics after the update
510        self.update_size_metrics();
511        update
512    }
513
514    /// Updates the entire pool after a new block was mined.
515    ///
516    /// This removes all mined transactions, updates according to the new base fee and rechecks
517    /// sender allowance.
518    pub(crate) fn on_canonical_state_change(
519        &mut self,
520        block_info: BlockInfo,
521        mined_transactions: Vec<TxHash>,
522        changed_senders: FxHashMap<SenderId, SenderInfo>,
523        update_kind: PoolUpdateKind,
524    ) -> OnNewCanonicalStateOutcome<T::Transaction> {
525        // update block info
526        let block_hash = block_info.last_seen_block_hash;
527        self.all_transactions.set_block_info(block_info);
528
529        // Remove all transaction that were included in the block
530        let mut removed_txs_count = 0;
531        for tx_hash in &mined_transactions {
532            if self.prune_transaction_by_hash(tx_hash).is_some() {
533                removed_txs_count += 1;
534            }
535        }
536
537        // Update removed transactions metric
538        self.metrics.removed_transactions.increment(removed_txs_count);
539
540        let UpdateOutcome { promoted, discarded } = self.update_accounts(changed_senders);
541
542        self.update_transaction_type_metrics();
543        self.metrics.performed_state_updates.increment(1);
544
545        // Update the latest update kind
546        self.latest_update_kind = Some(update_kind);
547
548        OnNewCanonicalStateOutcome { block_hash, mined: mined_transactions, promoted, discarded }
549    }
550
551    /// Update sub-pools size metrics.
552    pub(crate) fn update_size_metrics(&self) {
553        let stats = self.size();
554        self.metrics.pending_pool_transactions.set(stats.pending as f64);
555        self.metrics.pending_pool_size_bytes.set(stats.pending_size as f64);
556        self.metrics.basefee_pool_transactions.set(stats.basefee as f64);
557        self.metrics.basefee_pool_size_bytes.set(stats.basefee_size as f64);
558        self.metrics.queued_pool_transactions.set(stats.queued as f64);
559        self.metrics.queued_pool_size_bytes.set(stats.queued_size as f64);
560        self.metrics.blob_pool_transactions.set(stats.blob as f64);
561        self.metrics.blob_pool_size_bytes.set(stats.blob_size as f64);
562        self.metrics.total_transactions.set(stats.total as f64);
563    }
564
565    /// Updates transaction type metrics for the entire pool.
566    pub(crate) fn update_transaction_type_metrics(&self) {
567        let mut legacy_count = 0;
568        let mut eip2930_count = 0;
569        let mut eip1559_count = 0;
570        let mut eip4844_count = 0;
571        let mut eip7702_count = 0;
572
573        for tx in self.all_transactions.transactions_iter() {
574            match tx.transaction.tx_type() {
575                LEGACY_TX_TYPE_ID => legacy_count += 1,
576                EIP2930_TX_TYPE_ID => eip2930_count += 1,
577                EIP1559_TX_TYPE_ID => eip1559_count += 1,
578                EIP4844_TX_TYPE_ID => eip4844_count += 1,
579                EIP7702_TX_TYPE_ID => eip7702_count += 1,
580                _ => {} // Ignore other types
581            }
582        }
583
584        self.metrics.total_legacy_transactions.set(legacy_count as f64);
585        self.metrics.total_eip2930_transactions.set(eip2930_count as f64);
586        self.metrics.total_eip1559_transactions.set(eip1559_count as f64);
587        self.metrics.total_eip4844_transactions.set(eip4844_count as f64);
588        self.metrics.total_eip7702_transactions.set(eip7702_count as f64);
589    }
590
591    /// Adds the transaction into the pool.
592    ///
593    /// This pool consists of four sub-pools: `Queued`, `Pending`, `BaseFee`, and `Blob`.
594    ///
595    /// The `Queued` pool contains transactions with gaps in its dependency tree: It requires
596    /// additional transactions that are note yet present in the pool. And transactions that the
597    /// sender can not afford with the current balance.
598    ///
599    /// The `Pending` pool contains all transactions that have no nonce gaps, and can be afforded by
600    /// the sender. It only contains transactions that are ready to be included in the pending
601    /// block. The pending pool contains all transactions that could be listed currently, but not
602    /// necessarily independently. However, this pool never contains transactions with nonce gaps. A
603    /// transaction is considered `ready` when it has the lowest nonce of all transactions from the
604    /// same sender. Which is equals to the chain nonce of the sender in the pending pool.
605    ///
606    /// The `BaseFee` pool contains transactions that currently can't satisfy the dynamic fee
607    /// requirement. With EIP-1559, transactions can become executable or not without any changes to
608    /// the sender's balance or nonce and instead their `feeCap` determines whether the
609    /// transaction is _currently_ (on the current state) ready or needs to be parked until the
610    /// `feeCap` satisfies the block's `baseFee`.
611    ///
612    /// The `Blob` pool contains _blob_ transactions that currently can't satisfy the dynamic fee
613    /// requirement, or blob fee requirement. Transactions become executable only if the
614    /// transaction `feeCap` is greater than the block's `baseFee` and the `maxBlobFee` is greater
615    /// than the block's `blobFee`.
616    pub(crate) fn add_transaction(
617        &mut self,
618        tx: ValidPoolTransaction<T::Transaction>,
619        on_chain_balance: U256,
620        on_chain_nonce: u64,
621    ) -> PoolResult<AddedTransaction<T::Transaction>> {
622        if self.contains(tx.hash()) {
623            return Err(PoolError::new(*tx.hash(), PoolErrorKind::AlreadyImported))
624        }
625
626        // Update sender info with balance and nonce
627        self.sender_info
628            .entry(tx.sender_id())
629            .or_default()
630            .update(on_chain_nonce, on_chain_balance);
631
632        match self.all_transactions.insert_tx(tx, on_chain_balance, on_chain_nonce) {
633            Ok(InsertOk { transaction, move_to, replaced_tx, updates, .. }) => {
634                // replace the new tx and remove the replaced in the subpool(s)
635                self.add_new_transaction(transaction.clone(), replaced_tx.clone(), move_to);
636                // Update inserted transactions metric
637                self.metrics.inserted_transactions.increment(1);
638                let UpdateOutcome { promoted, discarded } = self.process_updates(updates);
639
640                let replaced = replaced_tx.map(|(tx, _)| tx);
641
642                // This transaction was moved to the pending pool.
643                let res = if move_to.is_pending() {
644                    AddedTransaction::Pending(AddedPendingTransaction {
645                        transaction,
646                        promoted,
647                        discarded,
648                        replaced,
649                    })
650                } else {
651                    AddedTransaction::Parked { transaction, subpool: move_to, replaced }
652                };
653
654                // Update size metrics after adding and potentially moving transactions.
655                self.update_size_metrics();
656
657                Ok(res)
658            }
659            Err(err) => {
660                // Update invalid transactions metric
661                self.metrics.invalid_transactions.increment(1);
662                match err {
663                    InsertErr::Underpriced { existing: _, transaction } => Err(PoolError::new(
664                        *transaction.hash(),
665                        PoolErrorKind::ReplacementUnderpriced,
666                    )),
667                    InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap } => {
668                        Err(PoolError::new(
669                            *transaction.hash(),
670                            PoolErrorKind::FeeCapBelowMinimumProtocolFeeCap(fee_cap),
671                        ))
672                    }
673                    InsertErr::ExceededSenderTransactionsCapacity { transaction } => {
674                        Err(PoolError::new(
675                            *transaction.hash(),
676                            PoolErrorKind::SpammerExceededCapacity(transaction.sender()),
677                        ))
678                    }
679                    InsertErr::TxGasLimitMoreThanAvailableBlockGas {
680                        transaction,
681                        block_gas_limit,
682                        tx_gas_limit,
683                    } => Err(PoolError::new(
684                        *transaction.hash(),
685                        PoolErrorKind::InvalidTransaction(
686                            InvalidPoolTransactionError::ExceedsGasLimit(
687                                tx_gas_limit,
688                                block_gas_limit,
689                            ),
690                        ),
691                    )),
692                    InsertErr::BlobTxHasNonceGap { transaction } => Err(PoolError::new(
693                        *transaction.hash(),
694                        PoolErrorKind::InvalidTransaction(
695                            Eip4844PoolTransactionError::Eip4844NonceGap.into(),
696                        ),
697                    )),
698                    InsertErr::Overdraft { transaction } => Err(PoolError::new(
699                        *transaction.hash(),
700                        PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Overdraft {
701                            cost: *transaction.cost(),
702                            balance: on_chain_balance,
703                        }),
704                    )),
705                    InsertErr::TxTypeConflict { transaction } => Err(PoolError::new(
706                        *transaction.hash(),
707                        PoolErrorKind::ExistingConflictingTransactionType(
708                            transaction.sender(),
709                            transaction.tx_type(),
710                        ),
711                    )),
712                }
713            }
714        }
715    }
716
717    /// Maintenance task to apply a series of updates.
718    ///
719    /// This will move/discard the given transaction according to the `PoolUpdate`
720    fn process_updates(&mut self, updates: Vec<PoolUpdate>) -> UpdateOutcome<T::Transaction> {
721        let mut outcome = UpdateOutcome::default();
722        for PoolUpdate { id, hash, current, destination } in updates {
723            match destination {
724                Destination::Discard => {
725                    // remove the transaction from the pool and subpool
726                    if let Some(tx) = self.prune_transaction_by_hash(&hash) {
727                        outcome.discarded.push(tx);
728                    }
729                    self.metrics.removed_transactions.increment(1);
730                }
731                Destination::Pool(move_to) => {
732                    debug_assert_ne!(&move_to, &current, "destination must be different");
733                    let moved = self.move_transaction(current, move_to, &id);
734                    if matches!(move_to, SubPool::Pending) {
735                        if let Some(tx) = moved {
736                            trace!(target: "txpool", hash=%tx.transaction.hash(), "Promoted transaction to pending");
737                            outcome.promoted.push(tx);
738                        }
739                    }
740                }
741            }
742        }
743        outcome
744    }
745
746    /// Moves a transaction from one sub pool to another.
747    ///
748    /// This will remove the given transaction from one sub-pool and insert it into the other
749    /// sub-pool.
750    fn move_transaction(
751        &mut self,
752        from: SubPool,
753        to: SubPool,
754        id: &TransactionId,
755    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
756        let tx = self.remove_from_subpool(from, id)?;
757        self.add_transaction_to_subpool(to, tx.clone());
758        Some(tx)
759    }
760
761    /// Removes and returns all matching transactions from the pool.
762    ///
763    /// Note: this does not advance any descendants of the removed transactions and does not apply
764    /// any additional updates.
765    pub(crate) fn remove_transactions(
766        &mut self,
767        hashes: Vec<TxHash>,
768    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
769        let txs =
770            hashes.into_iter().filter_map(|hash| self.remove_transaction_by_hash(&hash)).collect();
771        self.update_size_metrics();
772        txs
773    }
774
775    /// Removes and returns all matching transactions and their descendants from the pool.
776    pub(crate) fn remove_transactions_and_descendants(
777        &mut self,
778        hashes: Vec<TxHash>,
779    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
780        let mut removed = Vec::new();
781        for hash in hashes {
782            if let Some(tx) = self.remove_transaction_by_hash(&hash) {
783                removed.push(tx.clone());
784                self.remove_descendants(tx.id(), &mut removed);
785            }
786        }
787        self.update_size_metrics();
788        removed
789    }
790
791    /// Removes all transactions from the given sender.
792    pub(crate) fn remove_transactions_by_sender(
793        &mut self,
794        sender_id: SenderId,
795    ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
796        let mut removed = Vec::new();
797        let txs = self.get_transactions_by_sender(sender_id);
798        for tx in txs {
799            if let Some(tx) = self.remove_transaction(tx.id()) {
800                removed.push(tx);
801            }
802        }
803        self.update_size_metrics();
804        removed
805    }
806
807    /// Remove the transaction from the __entire__ pool.
808    ///
809    /// This includes the total set of transaction and the subpool it currently resides in.
810    fn remove_transaction(
811        &mut self,
812        id: &TransactionId,
813    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
814        let (tx, pool) = self.all_transactions.remove_transaction(id)?;
815        self.remove_from_subpool(pool, tx.id())
816    }
817
818    /// Remove the transaction from the entire pool via its hash.
819    ///
820    /// This includes the total set of transactions and the subpool it currently resides in.
821    fn remove_transaction_by_hash(
822        &mut self,
823        tx_hash: &B256,
824    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
825        let (tx, pool) = self.all_transactions.remove_transaction_by_hash(tx_hash)?;
826        self.remove_from_subpool(pool, tx.id())
827    }
828
829    /// This removes the transaction from the pool and advances any descendant state inside the
830    /// subpool.
831    ///
832    /// This is intended to be used when a transaction is included in a block,
833    /// [`Self::on_canonical_state_change`]
834    fn prune_transaction_by_hash(
835        &mut self,
836        tx_hash: &B256,
837    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
838        let (tx, pool) = self.all_transactions.remove_transaction_by_hash(tx_hash)?;
839        self.prune_from_subpool(pool, tx.id())
840    }
841
842    /// Removes the transaction from the given pool.
843    ///
844    /// Caution: this only removes the tx from the sub-pool and not from the pool itself
845    fn remove_from_subpool(
846        &mut self,
847        pool: SubPool,
848        tx: &TransactionId,
849    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
850        let tx = match pool {
851            SubPool::Queued => self.queued_pool.remove_transaction(tx),
852            SubPool::Pending => self.pending_pool.remove_transaction(tx),
853            SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
854            SubPool::Blob => self.blob_pool.remove_transaction(tx),
855        };
856
857        if let Some(ref tx) = tx {
858            // We trace here instead of in subpool structs directly, because the `ParkedPool` type
859            // is generic and it would not be possible to distinguish whether a transaction is
860            // being removed from the `BaseFee` pool, or the `Queued` pool.
861            trace!(target: "txpool", hash=%tx.transaction.hash(), ?pool, "Removed transaction from a subpool");
862        }
863
864        tx
865    }
866
867    /// Removes the transaction from the given pool and advance sub-pool internal state, with the
868    /// expectation that the given transaction is included in a block.
869    fn prune_from_subpool(
870        &mut self,
871        pool: SubPool,
872        tx: &TransactionId,
873    ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
874        let tx = match pool {
875            SubPool::Pending => self.pending_pool.remove_transaction(tx),
876            SubPool::Queued => self.queued_pool.remove_transaction(tx),
877            SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
878            SubPool::Blob => self.blob_pool.remove_transaction(tx),
879        };
880
881        if let Some(ref tx) = tx {
882            // We trace here instead of in subpool structs directly, because the `ParkedPool` type
883            // is generic and it would not be possible to distinguish whether a transaction is
884            // being pruned from the `BaseFee` pool, or the `Queued` pool.
885            trace!(target: "txpool", hash=%tx.transaction.hash(), ?pool, "Pruned transaction from a subpool");
886        }
887
888        tx
889    }
890
891    /// Removes _only_ the descendants of the given transaction from the __entire__ pool.
892    ///
893    /// All removed transactions are added to the `removed` vec.
894    fn remove_descendants(
895        &mut self,
896        tx: &TransactionId,
897        removed: &mut Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
898    ) {
899        let mut id = *tx;
900
901        // this will essentially pop _all_ descendant transactions one by one
902        loop {
903            let descendant =
904                self.all_transactions.descendant_txs_exclusive(&id).map(|(id, _)| *id).next();
905            if let Some(descendant) = descendant {
906                if let Some(tx) = self.remove_transaction(&descendant) {
907                    removed.push(tx)
908                }
909                id = descendant;
910            } else {
911                return
912            }
913        }
914    }
915
916    /// Inserts the transaction into the given sub-pool.
917    fn add_transaction_to_subpool(
918        &mut self,
919        pool: SubPool,
920        tx: Arc<ValidPoolTransaction<T::Transaction>>,
921    ) {
922        // We trace here instead of in structs directly, because the `ParkedPool` type is
923        // generic and it would not be possible to distinguish whether a transaction is being
924        // added to the `BaseFee` pool, or the `Queued` pool.
925        match pool {
926            SubPool::Queued => self.queued_pool.add_transaction(tx),
927            SubPool::Pending => {
928                self.pending_pool.add_transaction(tx, self.all_transactions.pending_fees.base_fee);
929            }
930            SubPool::BaseFee => self.basefee_pool.add_transaction(tx),
931            SubPool::Blob => self.blob_pool.add_transaction(tx),
932        }
933    }
934
935    /// Inserts the transaction into the given sub-pool.
936    /// Optionally, removes the replacement transaction.
937    fn add_new_transaction(
938        &mut self,
939        transaction: Arc<ValidPoolTransaction<T::Transaction>>,
940        replaced: Option<(Arc<ValidPoolTransaction<T::Transaction>>, SubPool)>,
941        pool: SubPool,
942    ) {
943        if let Some((replaced, replaced_pool)) = replaced {
944            // Remove the replaced transaction
945            self.remove_from_subpool(replaced_pool, replaced.id());
946        }
947
948        self.add_transaction_to_subpool(pool, transaction)
949    }
950
951    /// Ensures that the transactions in the sub-pools are within the given bounds.
952    ///
953    /// If the current size exceeds the given bounds, the worst transactions are evicted from the
954    /// pool and returned.
955    ///
956    /// This returns all transactions that were removed from the entire pool.
957    pub(crate) fn discard_worst(&mut self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
958        let mut removed = Vec::new();
959
960        // Helper macro that discards the worst transactions for the pools
961        macro_rules! discard_worst {
962            ($this:ident, $removed:ident, [$($limit:ident => $pool:ident),* $(,)*]) => {
963                $ (
964                while $this.$pool.exceeds(&$this.config.$limit)
965                    {
966                        trace!(
967                            target: "txpool",
968                            "discarding transactions from {}, limit: {:?}, curr size: {}, curr len: {}",
969                            stringify!($pool),
970                            $this.config.$limit,
971                            $this.$pool.size(),
972                            $this.$pool.len(),
973                        );
974
975                        // 1. first remove the worst transaction from the subpool
976                        let removed_from_subpool = $this.$pool.truncate_pool($this.config.$limit.clone());
977
978                        trace!(
979                            target: "txpool",
980                            "removed {} transactions from {}, limit: {:?}, curr size: {}, curr len: {}",
981                            removed_from_subpool.len(),
982                            stringify!($pool),
983                            $this.config.$limit,
984                            $this.$pool.size(),
985                            $this.$pool.len()
986                        );
987
988                        // 2. remove all transactions from the total set
989                        for tx in removed_from_subpool {
990                            $this.all_transactions.remove_transaction(tx.id());
991
992                            let id = *tx.id();
993
994                            // keep track of removed transaction
995                            removed.push(tx);
996
997                            // 3. remove all its descendants from the entire pool
998                            $this.remove_descendants(&id, &mut $removed);
999                        }
1000                    }
1001
1002                )*
1003            };
1004        }
1005
1006        discard_worst!(
1007            self, removed, [
1008                pending_limit => pending_pool,
1009                basefee_limit => basefee_pool,
1010                blob_limit    => blob_pool,
1011                queued_limit  => queued_pool,
1012            ]
1013        );
1014
1015        removed
1016    }
1017
1018    /// Number of transactions in the entire pool
1019    pub(crate) fn len(&self) -> usize {
1020        self.all_transactions.len()
1021    }
1022
1023    /// Whether the pool is empty
1024    pub(crate) fn is_empty(&self) -> bool {
1025        self.all_transactions.is_empty()
1026    }
1027
1028    /// Asserts all invariants of the  pool's:
1029    ///
1030    ///  - All maps are bijections (`by_id`, `by_hash`)
1031    ///  - Total size is equal to the sum of all sub-pools
1032    ///
1033    /// # Panics
1034    /// if any invariant is violated
1035    #[cfg(any(test, feature = "test-utils"))]
1036    pub fn assert_invariants(&self) {
1037        let size = self.size();
1038        let actual = size.basefee + size.pending + size.queued + size.blob;
1039        assert_eq!(size.total, actual, "total size must be equal to the sum of all sub-pools, basefee:{}, pending:{}, queued:{}, blob:{}", size.basefee, size.pending, size.queued, size.blob);
1040        self.all_transactions.assert_invariants();
1041        self.pending_pool.assert_invariants();
1042        self.basefee_pool.assert_invariants();
1043        self.queued_pool.assert_invariants();
1044        self.blob_pool.assert_invariants();
1045    }
1046}
1047
1048#[cfg(any(test, feature = "test-utils"))]
1049impl TxPool<crate::test_utils::MockOrdering> {
1050    /// Creates a mock instance for testing.
1051    pub fn mock() -> Self {
1052        Self::new(crate::test_utils::MockOrdering::default(), PoolConfig::default())
1053    }
1054}
1055
1056#[cfg(test)]
1057impl<T: TransactionOrdering> Drop for TxPool<T> {
1058    fn drop(&mut self) {
1059        self.assert_invariants();
1060    }
1061}
1062
1063// Additional test impls
1064#[cfg(any(test, feature = "test-utils"))]
1065#[allow(dead_code)]
1066impl<T: TransactionOrdering> TxPool<T> {
1067    pub(crate) const fn pending(&self) -> &PendingPool<T> {
1068        &self.pending_pool
1069    }
1070
1071    pub(crate) const fn base_fee(&self) -> &ParkedPool<BasefeeOrd<T::Transaction>> {
1072        &self.basefee_pool
1073    }
1074
1075    pub(crate) const fn queued(&self) -> &ParkedPool<QueuedOrd<T::Transaction>> {
1076        &self.queued_pool
1077    }
1078}
1079
1080impl<T: TransactionOrdering> fmt::Debug for TxPool<T> {
1081    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1082        f.debug_struct("TxPool").field("config", &self.config).finish_non_exhaustive()
1083    }
1084}
1085
1086/// Container for _all_ transaction in the pool.
1087///
1088/// This is the sole entrypoint that's guarding all sub-pools, all sub-pool actions are always
1089/// derived from this set. Updates returned from this type must be applied to the sub-pools.
1090pub(crate) struct AllTransactions<T: PoolTransaction> {
1091    /// Minimum base fee required by the protocol.
1092    ///
1093    /// Transactions with a lower base fee will never be included by the chain
1094    minimal_protocol_basefee: u64,
1095    /// The max gas limit of the block
1096    block_gas_limit: u64,
1097    /// Max number of executable transaction slots guaranteed per account
1098    max_account_slots: usize,
1099    /// _All_ transactions identified by their hash.
1100    by_hash: HashMap<TxHash, Arc<ValidPoolTransaction<T>>>,
1101    /// _All_ transaction in the pool sorted by their sender and nonce pair.
1102    txs: BTreeMap<TransactionId, PoolInternalTransaction<T>>,
1103    /// Tracks the number of transactions by sender that are currently in the pool.
1104    tx_counter: FxHashMap<SenderId, usize>,
1105    /// The current block number the pool keeps track of.
1106    last_seen_block_number: u64,
1107    /// The current block hash the pool keeps track of.
1108    last_seen_block_hash: B256,
1109    /// Expected blob and base fee for the pending block.
1110    pending_fees: PendingFees,
1111    /// Configured price bump settings for replacements
1112    price_bumps: PriceBumpConfig,
1113    /// How to handle [`TransactionOrigin::Local`](crate::TransactionOrigin) transactions.
1114    local_transactions_config: LocalTransactionConfig,
1115    /// All Transactions metrics
1116    metrics: AllTransactionsMetrics,
1117}
1118
1119impl<T: PoolTransaction> AllTransactions<T> {
1120    /// Create a new instance
1121    fn new(config: &PoolConfig) -> Self {
1122        Self {
1123            max_account_slots: config.max_account_slots,
1124            price_bumps: config.price_bumps,
1125            local_transactions_config: config.local_transactions_config.clone(),
1126            minimal_protocol_basefee: config.minimal_protocol_basefee,
1127            block_gas_limit: config.gas_limit,
1128            ..Default::default()
1129        }
1130    }
1131
1132    /// Returns an iterator over all _unique_ hashes in the pool
1133    #[allow(dead_code)]
1134    pub(crate) fn hashes_iter(&self) -> impl Iterator<Item = TxHash> + '_ {
1135        self.by_hash.keys().copied()
1136    }
1137
1138    /// Returns an iterator over all transactions in the pool
1139    pub(crate) fn transactions_iter(
1140        &self,
1141    ) -> impl Iterator<Item = &Arc<ValidPoolTransaction<T>>> + '_ {
1142        self.by_hash.values()
1143    }
1144
1145    /// Returns if the transaction for the given hash is already included in this pool
1146    pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
1147        self.by_hash.contains_key(tx_hash)
1148    }
1149
1150    /// Returns the internal transaction with additional metadata
1151    pub(crate) fn get(&self, id: &TransactionId) -> Option<&PoolInternalTransaction<T>> {
1152        self.txs.get(id)
1153    }
1154
1155    /// Increments the transaction counter for the sender
1156    pub(crate) fn tx_inc(&mut self, sender: SenderId) {
1157        let count = self.tx_counter.entry(sender).or_default();
1158        *count += 1;
1159        self.metrics.all_transactions_by_all_senders.increment(1.0);
1160    }
1161
1162    /// Decrements the transaction counter for the sender
1163    pub(crate) fn tx_decr(&mut self, sender: SenderId) {
1164        if let hash_map::Entry::Occupied(mut entry) = self.tx_counter.entry(sender) {
1165            let count = entry.get_mut();
1166            if *count == 1 {
1167                entry.remove();
1168                self.metrics.all_transactions_by_all_senders.decrement(1.0);
1169                return
1170            }
1171            *count -= 1;
1172            self.metrics.all_transactions_by_all_senders.decrement(1.0);
1173        }
1174    }
1175
1176    /// Updates the block specific info
1177    fn set_block_info(&mut self, block_info: BlockInfo) {
1178        let BlockInfo {
1179            block_gas_limit,
1180            last_seen_block_hash,
1181            last_seen_block_number,
1182            pending_basefee,
1183            pending_blob_fee,
1184        } = block_info;
1185        self.last_seen_block_number = last_seen_block_number;
1186        self.last_seen_block_hash = last_seen_block_hash;
1187
1188        self.pending_fees.base_fee = pending_basefee;
1189        self.metrics.base_fee.set(pending_basefee as f64);
1190
1191        self.block_gas_limit = block_gas_limit;
1192
1193        if let Some(pending_blob_fee) = pending_blob_fee {
1194            self.pending_fees.blob_fee = pending_blob_fee;
1195            self.metrics.blob_base_fee.set(pending_blob_fee as f64);
1196        }
1197    }
1198
1199    /// Updates the size metrics
1200    pub(crate) fn update_size_metrics(&self) {
1201        self.metrics.all_transactions_by_hash.set(self.by_hash.len() as f64);
1202        self.metrics.all_transactions_by_id.set(self.txs.len() as f64);
1203    }
1204
1205    /// Rechecks all transactions in the pool against the changes.
1206    ///
1207    /// Possible changes are:
1208    ///
1209    /// For all transactions:
1210    ///   - decreased basefee: promotes from `basefee` to `pending` sub-pool.
1211    ///   - increased basefee: demotes from `pending` to `basefee` sub-pool.
1212    ///
1213    /// Individually:
1214    ///   - decreased sender allowance: demote from (`basefee`|`pending`) to `queued`.
1215    ///   - increased sender allowance: promote from `queued` to
1216    ///       - `pending` if basefee condition is met.
1217    ///       - `basefee` if basefee condition is _not_ met.
1218    ///
1219    /// Additionally, this will also update the `cumulative_gas_used` for transactions of a sender
1220    /// that got transaction included in the block.
1221    pub(crate) fn update(
1222        &mut self,
1223        changed_accounts: &FxHashMap<SenderId, SenderInfo>,
1224    ) -> Vec<PoolUpdate> {
1225        // pre-allocate a few updates
1226        let mut updates = Vec::with_capacity(64);
1227
1228        let mut iter = self.txs.iter_mut().peekable();
1229
1230        // Loop over all individual senders and update all affected transactions.
1231        // One sender may have up to `max_account_slots` transactions here, which means, worst case
1232        // `max_accounts_slots` need to be updated, for example if the first transaction is blocked
1233        // due to too low base fee.
1234        // However, we don't have to necessarily check every transaction of a sender. If no updates
1235        // are possible (nonce gap) then we can skip to the next sender.
1236
1237        // The `unique_sender` loop will process the first transaction of all senders, update its
1238        // state and internally update all consecutive transactions
1239        'transactions: while let Some((id, tx)) = iter.next() {
1240            macro_rules! next_sender {
1241                ($iter:ident) => {
1242                    'this: while let Some((peek, _)) = iter.peek() {
1243                        if peek.sender != id.sender {
1244                            break 'this
1245                        }
1246                        iter.next();
1247                    }
1248                };
1249            }
1250            // tracks the balance if the sender was changed in the block
1251            let mut changed_balance = None;
1252
1253            // check if this is a changed account
1254            if let Some(info) = changed_accounts.get(&id.sender) {
1255                // discard all transactions with a nonce lower than the current state nonce
1256                if id.nonce < info.state_nonce {
1257                    updates.push(PoolUpdate {
1258                        id: *tx.transaction.id(),
1259                        hash: *tx.transaction.hash(),
1260                        current: tx.subpool,
1261                        destination: Destination::Discard,
1262                    });
1263                    continue 'transactions
1264                }
1265
1266                let ancestor = TransactionId::ancestor(id.nonce, info.state_nonce, id.sender);
1267                // If there's no ancestor then this is the next transaction.
1268                if ancestor.is_none() {
1269                    tx.state.insert(TxState::NO_NONCE_GAPS);
1270                    tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1271                    tx.cumulative_cost = U256::ZERO;
1272                    if tx.transaction.cost() > &info.balance {
1273                        // sender lacks sufficient funds to pay for this transaction
1274                        tx.state.remove(TxState::ENOUGH_BALANCE);
1275                    } else {
1276                        tx.state.insert(TxState::ENOUGH_BALANCE);
1277                    }
1278                }
1279
1280                changed_balance = Some(&info.balance);
1281            }
1282
1283            // If there's a nonce gap, we can shortcircuit, because there's nothing to update yet.
1284            if tx.state.has_nonce_gap() {
1285                next_sender!(iter);
1286                continue 'transactions
1287            }
1288
1289            // Since this is the first transaction of the sender, it has no parked ancestors
1290            tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1291
1292            // Update the first transaction of this sender.
1293            Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1294            // Track if the transaction's sub-pool changed.
1295            Self::record_subpool_update(&mut updates, tx);
1296
1297            // Track blocking transactions.
1298            let mut has_parked_ancestor = !tx.state.is_pending();
1299
1300            let mut cumulative_cost = tx.next_cumulative_cost();
1301
1302            // the next expected nonce after this transaction: nonce + 1
1303            let mut next_nonce_in_line = tx.transaction.nonce().saturating_add(1);
1304
1305            // Update all consecutive transaction of this sender
1306            while let Some((peek, ref mut tx)) = iter.peek_mut() {
1307                if peek.sender != id.sender {
1308                    // Found the next sender we need to check
1309                    continue 'transactions
1310                }
1311
1312                if tx.transaction.nonce() == next_nonce_in_line {
1313                    // no longer nonce gapped
1314                    tx.state.insert(TxState::NO_NONCE_GAPS);
1315                } else {
1316                    // can short circuit if there's still a nonce gap
1317                    next_sender!(iter);
1318                    continue 'transactions
1319                }
1320
1321                // update for next iteration of this sender's loop
1322                next_nonce_in_line = next_nonce_in_line.saturating_add(1);
1323
1324                // update cumulative cost
1325                tx.cumulative_cost = cumulative_cost;
1326                // Update for next transaction
1327                cumulative_cost = tx.next_cumulative_cost();
1328
1329                // If the account changed in the block, check the balance.
1330                if let Some(changed_balance) = changed_balance {
1331                    if &cumulative_cost > changed_balance {
1332                        // sender lacks sufficient funds to pay for this transaction
1333                        tx.state.remove(TxState::ENOUGH_BALANCE);
1334                    } else {
1335                        tx.state.insert(TxState::ENOUGH_BALANCE);
1336                    }
1337                }
1338
1339                // Update ancestor condition.
1340                if has_parked_ancestor {
1341                    tx.state.remove(TxState::NO_PARKED_ANCESTORS);
1342                } else {
1343                    tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1344                }
1345                has_parked_ancestor = !tx.state.is_pending();
1346
1347                // Update and record sub-pool changes.
1348                Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1349                Self::record_subpool_update(&mut updates, tx);
1350
1351                // Advance iterator
1352                iter.next();
1353            }
1354        }
1355
1356        updates
1357    }
1358
1359    /// This will update the transaction's `subpool` based on its state.
1360    ///
1361    /// If the sub-pool derived from the state differs from the current pool, it will record a
1362    /// `PoolUpdate` for this transaction to move it to the new sub-pool.
1363    fn record_subpool_update(updates: &mut Vec<PoolUpdate>, tx: &mut PoolInternalTransaction<T>) {
1364        let current_pool = tx.subpool;
1365        tx.subpool = tx.state.into();
1366        if current_pool != tx.subpool {
1367            updates.push(PoolUpdate {
1368                id: *tx.transaction.id(),
1369                hash: *tx.transaction.hash(),
1370                current: current_pool,
1371                destination: tx.subpool.into(),
1372            })
1373        }
1374    }
1375
1376    /// Rechecks the transaction's dynamic fee condition.
1377    fn update_tx_base_fee(pending_block_base_fee: u64, tx: &mut PoolInternalTransaction<T>) {
1378        // Recheck dynamic fee condition.
1379        match tx.transaction.max_fee_per_gas().cmp(&(pending_block_base_fee as u128)) {
1380            Ordering::Greater | Ordering::Equal => {
1381                tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
1382            }
1383            Ordering::Less => {
1384                tx.state.remove(TxState::ENOUGH_FEE_CAP_BLOCK);
1385            }
1386        }
1387    }
1388
1389    /// Returns an iterator over all transactions for the given sender, starting with the lowest
1390    /// nonce
1391    pub(crate) fn txs_iter(
1392        &self,
1393        sender: SenderId,
1394    ) -> impl Iterator<Item = (&TransactionId, &PoolInternalTransaction<T>)> + '_ {
1395        self.txs
1396            .range((sender.start_bound(), Unbounded))
1397            .take_while(move |(other, _)| sender == other.sender)
1398    }
1399
1400    /// Returns a mutable iterator over all transactions for the given sender, starting with the
1401    /// lowest nonce
1402    #[cfg(test)]
1403    #[allow(dead_code)]
1404    pub(crate) fn txs_iter_mut(
1405        &mut self,
1406        sender: SenderId,
1407    ) -> impl Iterator<Item = (&TransactionId, &mut PoolInternalTransaction<T>)> + '_ {
1408        self.txs
1409            .range_mut((sender.start_bound(), Unbounded))
1410            .take_while(move |(other, _)| sender == other.sender)
1411    }
1412
1413    /// Returns all transactions that _follow_ after the given id and have the same sender.
1414    ///
1415    /// NOTE: The range is _exclusive_
1416    pub(crate) fn descendant_txs_exclusive<'a, 'b: 'a>(
1417        &'a self,
1418        id: &'b TransactionId,
1419    ) -> impl Iterator<Item = (&'a TransactionId, &'a PoolInternalTransaction<T>)> + 'a {
1420        self.txs.range((Excluded(id), Unbounded)).take_while(|(other, _)| id.sender == other.sender)
1421    }
1422
1423    /// Returns all transactions that _follow_ after the given id but have the same sender.
1424    ///
1425    /// NOTE: The range is _inclusive_: if the transaction that belongs to `id` it will be the
1426    /// first value.
1427    pub(crate) fn descendant_txs_inclusive<'a, 'b: 'a>(
1428        &'a self,
1429        id: &'b TransactionId,
1430    ) -> impl Iterator<Item = (&'a TransactionId, &'a PoolInternalTransaction<T>)> + 'a {
1431        self.txs.range(id..).take_while(|(other, _)| id.sender == other.sender)
1432    }
1433
1434    /// Returns all mutable transactions that _follow_ after the given id but have the same sender.
1435    ///
1436    /// NOTE: The range is _inclusive_: if the transaction that belongs to `id` it field be the
1437    /// first value.
1438    pub(crate) fn descendant_txs_mut<'a, 'b: 'a>(
1439        &'a mut self,
1440        id: &'b TransactionId,
1441    ) -> impl Iterator<Item = (&'a TransactionId, &'a mut PoolInternalTransaction<T>)> + 'a {
1442        self.txs.range_mut(id..).take_while(|(other, _)| id.sender == other.sender)
1443    }
1444
1445    /// Removes a transaction from the set using its hash.
1446    pub(crate) fn remove_transaction_by_hash(
1447        &mut self,
1448        tx_hash: &B256,
1449    ) -> Option<(Arc<ValidPoolTransaction<T>>, SubPool)> {
1450        let tx = self.by_hash.remove(tx_hash)?;
1451        let internal = self.txs.remove(&tx.transaction_id)?;
1452        // decrement the counter for the sender.
1453        self.tx_decr(tx.sender_id());
1454        self.update_size_metrics();
1455        Some((tx, internal.subpool))
1456    }
1457
1458    /// Removes a transaction from the set.
1459    ///
1460    /// This will _not_ trigger additional updates, because descendants without nonce gaps are
1461    /// already in the pending pool, and this transaction will be the first transaction of the
1462    /// sender in this pool.
1463    pub(crate) fn remove_transaction(
1464        &mut self,
1465        id: &TransactionId,
1466    ) -> Option<(Arc<ValidPoolTransaction<T>>, SubPool)> {
1467        let internal = self.txs.remove(id)?;
1468
1469        // decrement the counter for the sender.
1470        self.tx_decr(internal.transaction.sender_id());
1471
1472        let result =
1473            self.by_hash.remove(internal.transaction.hash()).map(|tx| (tx, internal.subpool));
1474
1475        self.update_size_metrics();
1476
1477        result
1478    }
1479
1480    /// Checks if the given transaction's type conflicts with an existing transaction.
1481    ///
1482    /// See also [`ValidPoolTransaction::tx_type_conflicts_with`].
1483    ///
1484    /// Caution: This assumes that mutually exclusive invariant is always true for the same sender.
1485    #[inline]
1486    fn contains_conflicting_transaction(&self, tx: &ValidPoolTransaction<T>) -> bool {
1487        self.txs_iter(tx.transaction_id.sender)
1488            .next()
1489            .is_some_and(|(_, existing)| tx.tx_type_conflicts_with(&existing.transaction))
1490    }
1491
1492    /// Additional checks for a new transaction.
1493    ///
1494    /// This will enforce all additional rules in the context of this pool, such as:
1495    ///   - Spam protection: reject new non-local transaction from a sender that exhausted its slot
1496    ///     capacity.
1497    ///   - Gas limit: reject transactions if they exceed a block's maximum gas.
1498    ///   - Ensures transaction types are not conflicting for the sender: blob vs normal
1499    ///     transactions are mutually exclusive for the same sender.
1500    fn ensure_valid(
1501        &self,
1502        transaction: ValidPoolTransaction<T>,
1503        on_chain_nonce: u64,
1504    ) -> Result<ValidPoolTransaction<T>, InsertErr<T>> {
1505        if !self.local_transactions_config.is_local(transaction.origin, transaction.sender_ref()) {
1506            let current_txs =
1507                self.tx_counter.get(&transaction.sender_id()).copied().unwrap_or_default();
1508
1509            // Reject transactions if sender's capacity is exceeded.
1510            // If transaction's nonce matches on-chain nonce always let it through
1511            if current_txs >= self.max_account_slots && transaction.nonce() > on_chain_nonce {
1512                return Err(InsertErr::ExceededSenderTransactionsCapacity {
1513                    transaction: Arc::new(transaction),
1514                })
1515            }
1516        }
1517        if transaction.gas_limit() > self.block_gas_limit {
1518            return Err(InsertErr::TxGasLimitMoreThanAvailableBlockGas {
1519                block_gas_limit: self.block_gas_limit,
1520                tx_gas_limit: transaction.gas_limit(),
1521                transaction: Arc::new(transaction),
1522            })
1523        }
1524
1525        if self.contains_conflicting_transaction(&transaction) {
1526            // blob vs non blob transactions are mutually exclusive for the same sender
1527            return Err(InsertErr::TxTypeConflict { transaction: Arc::new(transaction) })
1528        }
1529
1530        Ok(transaction)
1531    }
1532
1533    /// Enforces additional constraints for blob transactions before attempting to insert:
1534    ///    - new blob transactions must not have any nonce gaps
1535    ///    - blob transactions cannot go into overdraft
1536    ///    - replacement blob transaction with a higher fee must not shift an already propagated
1537    ///      descending blob transaction into overdraft
1538    fn ensure_valid_blob_transaction(
1539        &self,
1540        new_blob_tx: ValidPoolTransaction<T>,
1541        on_chain_balance: U256,
1542        ancestor: Option<TransactionId>,
1543    ) -> Result<ValidPoolTransaction<T>, InsertErr<T>> {
1544        if let Some(ancestor) = ancestor {
1545            let Some(ancestor_tx) = self.txs.get(&ancestor) else {
1546                // ancestor tx is missing, so we can't insert the new blob
1547                self.metrics.blob_transactions_nonce_gaps.increment(1);
1548                return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
1549            };
1550            if ancestor_tx.state.has_nonce_gap() {
1551                // the ancestor transaction already has a nonce gap, so we can't insert the new
1552                // blob
1553                self.metrics.blob_transactions_nonce_gaps.increment(1);
1554                return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
1555            }
1556
1557            // the max cost executing this transaction requires
1558            let mut cumulative_cost = ancestor_tx.next_cumulative_cost() + new_blob_tx.cost();
1559
1560            // check if the new blob would go into overdraft
1561            if cumulative_cost > on_chain_balance {
1562                // the transaction would go into overdraft
1563                return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1564            }
1565
1566            // ensure that a replacement would not shift already propagated blob transactions into
1567            // overdraft
1568            let id = new_blob_tx.transaction_id;
1569            let mut descendants = self.descendant_txs_inclusive(&id).peekable();
1570            if let Some((maybe_replacement, _)) = descendants.peek() {
1571                if **maybe_replacement == new_blob_tx.transaction_id {
1572                    // replacement transaction
1573                    descendants.next();
1574
1575                    // check if any of descendant blob transactions should be shifted into overdraft
1576                    for (_, tx) in descendants {
1577                        cumulative_cost += tx.transaction.cost();
1578                        if tx.transaction.is_eip4844() && cumulative_cost > on_chain_balance {
1579                            // the transaction would shift
1580                            return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1581                        }
1582                    }
1583                }
1584            }
1585        } else if new_blob_tx.cost() > &on_chain_balance {
1586            // the transaction would go into overdraft
1587            return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1588        }
1589
1590        Ok(new_blob_tx)
1591    }
1592
1593    /// Inserts a new _valid_ transaction into the pool.
1594    ///
1595    /// If the transaction already exists, it will be replaced if not underpriced.
1596    /// Returns info to which sub-pool the transaction should be moved.
1597    /// Also returns a set of pool updates triggered by this insert, that need to be handled by the
1598    /// caller.
1599    ///
1600    /// These can include:
1601    ///      - closing nonce gaps of descendant transactions
1602    ///      - enough balance updates
1603    ///
1604    /// Note: For EIP-4844 blob transactions additional constraints are enforced:
1605    ///      - new blob transactions must not have any nonce gaps
1606    ///      - blob transactions cannot go into overdraft
1607    ///
1608    /// ## Transaction type Exclusivity
1609    ///
1610    /// The pool enforces exclusivity of eip-4844 blob vs non-blob transactions on a per sender
1611    /// basis:
1612    ///  - If the pool already includes a blob transaction from the `transaction`'s sender, then the
1613    ///    `transaction` must also be a blob transaction
1614    ///  - If the pool already includes a non-blob transaction from the `transaction`'s sender, then
1615    ///    the `transaction` must _not_ be a blob transaction.
1616    ///
1617    /// In other words, the presence of blob transactions exclude non-blob transactions and vice
1618    /// versa.
1619    ///
1620    /// ## Replacements
1621    ///
1622    /// The replacement candidate must satisfy given price bump constraints: replacement candidate
1623    /// must not be underpriced
1624    pub(crate) fn insert_tx(
1625        &mut self,
1626        transaction: ValidPoolTransaction<T>,
1627        on_chain_balance: U256,
1628        on_chain_nonce: u64,
1629    ) -> InsertResult<T> {
1630        assert!(on_chain_nonce <= transaction.nonce(), "Invalid transaction");
1631
1632        let mut transaction = self.ensure_valid(transaction, on_chain_nonce)?;
1633
1634        let inserted_tx_id = *transaction.id();
1635        let mut state = TxState::default();
1636        let mut cumulative_cost = U256::ZERO;
1637        let mut updates = Vec::new();
1638
1639        // Current tx does not exceed block gas limit after ensure_valid check
1640        state.insert(TxState::NOT_TOO_MUCH_GAS);
1641
1642        // identifier of the ancestor transaction, will be None if the transaction is the next tx of
1643        // the sender
1644        let ancestor = TransactionId::ancestor(
1645            transaction.transaction.nonce(),
1646            on_chain_nonce,
1647            inserted_tx_id.sender,
1648        );
1649
1650        // before attempting to insert a blob transaction, we need to ensure that additional
1651        // constraints are met that only apply to blob transactions
1652        if transaction.is_eip4844() {
1653            state.insert(TxState::BLOB_TRANSACTION);
1654
1655            transaction =
1656                self.ensure_valid_blob_transaction(transaction, on_chain_balance, ancestor)?;
1657            let blob_fee_cap = transaction.transaction.max_fee_per_blob_gas().unwrap_or_default();
1658            if blob_fee_cap >= self.pending_fees.blob_fee {
1659                state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
1660            }
1661        } else {
1662            // Non-EIP4844 transaction always satisfy the blob fee cap condition
1663            state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
1664        }
1665
1666        let transaction = Arc::new(transaction);
1667
1668        // If there's no ancestor tx then this is the next transaction.
1669        if ancestor.is_none() {
1670            state.insert(TxState::NO_NONCE_GAPS);
1671            state.insert(TxState::NO_PARKED_ANCESTORS);
1672        }
1673
1674        // Check dynamic fee
1675        let fee_cap = transaction.max_fee_per_gas();
1676
1677        if fee_cap < self.minimal_protocol_basefee as u128 {
1678            return Err(InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap })
1679        }
1680        if fee_cap >= self.pending_fees.base_fee as u128 {
1681            state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
1682        }
1683
1684        // placeholder for the replaced transaction, if any
1685        let mut replaced_tx = None;
1686
1687        let pool_tx = PoolInternalTransaction {
1688            transaction: Arc::clone(&transaction),
1689            subpool: state.into(),
1690            state,
1691            cumulative_cost,
1692        };
1693
1694        // try to insert the transaction
1695        match self.txs.entry(*transaction.id()) {
1696            Entry::Vacant(entry) => {
1697                // Insert the transaction in both maps
1698                self.by_hash.insert(*pool_tx.transaction.hash(), pool_tx.transaction.clone());
1699                entry.insert(pool_tx);
1700            }
1701            Entry::Occupied(mut entry) => {
1702                // Transaction with the same nonce already exists: replacement candidate
1703                let existing_transaction = entry.get().transaction.as_ref();
1704                let maybe_replacement = transaction.as_ref();
1705
1706                // Ensure the new transaction is not underpriced
1707                if existing_transaction.is_underpriced(maybe_replacement, &self.price_bumps) {
1708                    return Err(InsertErr::Underpriced {
1709                        transaction: pool_tx.transaction,
1710                        existing: *entry.get().transaction.hash(),
1711                    })
1712                }
1713                let new_hash = *pool_tx.transaction.hash();
1714                let new_transaction = pool_tx.transaction.clone();
1715                let replaced = entry.insert(pool_tx);
1716                self.by_hash.remove(replaced.transaction.hash());
1717                self.by_hash.insert(new_hash, new_transaction);
1718                // also remove the hash
1719                replaced_tx = Some((replaced.transaction, replaced.subpool));
1720            }
1721        }
1722
1723        // The next transaction of this sender
1724        let on_chain_id = TransactionId::new(transaction.sender_id(), on_chain_nonce);
1725        {
1726            // Tracks the next nonce we expect if the transactions are gapless
1727            let mut next_nonce = on_chain_id.nonce;
1728
1729            // We need to find out if the next transaction of the sender is considered pending
1730            // The direct descendant has _no_ parked ancestors because the `on_chain_nonce` is
1731            // pending, so we can set this to `false`
1732            let mut has_parked_ancestor = false;
1733
1734            // Traverse all future transactions of the sender starting with the on chain nonce, and
1735            // update existing transactions: `[on_chain_nonce,..]`
1736            for (id, tx) in self.descendant_txs_mut(&on_chain_id) {
1737                let current_pool = tx.subpool;
1738
1739                // If there's a nonce gap, we can shortcircuit
1740                if next_nonce != id.nonce {
1741                    break
1742                }
1743
1744                // close the nonce gap
1745                tx.state.insert(TxState::NO_NONCE_GAPS);
1746
1747                // set cumulative cost
1748                tx.cumulative_cost = cumulative_cost;
1749
1750                // Update for next transaction
1751                cumulative_cost = tx.next_cumulative_cost();
1752
1753                if cumulative_cost > on_chain_balance {
1754                    // sender lacks sufficient funds to pay for this transaction
1755                    tx.state.remove(TxState::ENOUGH_BALANCE);
1756                } else {
1757                    tx.state.insert(TxState::ENOUGH_BALANCE);
1758                }
1759
1760                // Update ancestor condition.
1761                if has_parked_ancestor {
1762                    tx.state.remove(TxState::NO_PARKED_ANCESTORS);
1763                } else {
1764                    tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1765                }
1766                has_parked_ancestor = !tx.state.is_pending();
1767
1768                // update the pool based on the state
1769                tx.subpool = tx.state.into();
1770
1771                if inserted_tx_id.eq(id) {
1772                    // if it is the new transaction, track its updated state
1773                    state = tx.state;
1774                } else {
1775                    // check if anything changed
1776                    if current_pool != tx.subpool {
1777                        updates.push(PoolUpdate {
1778                            id: *id,
1779                            hash: *tx.transaction.hash(),
1780                            current: current_pool,
1781                            destination: tx.subpool.into(),
1782                        })
1783                    }
1784                }
1785
1786                // increment for next iteration
1787                next_nonce = id.next_nonce();
1788            }
1789        }
1790
1791        // If this wasn't a replacement transaction we need to update the counter.
1792        if replaced_tx.is_none() {
1793            self.tx_inc(inserted_tx_id.sender);
1794        }
1795
1796        self.update_size_metrics();
1797
1798        let res = Ok(InsertOk { transaction, move_to: state.into(), state, replaced_tx, updates });
1799        res
1800    }
1801
1802    /// Number of transactions in the entire pool
1803    pub(crate) fn len(&self) -> usize {
1804        self.txs.len()
1805    }
1806
1807    /// Whether the pool is empty
1808    pub(crate) fn is_empty(&self) -> bool {
1809        self.txs.is_empty()
1810    }
1811
1812    /// Asserts that the bijection between `by_hash` and `txs` is valid.
1813    #[cfg(any(test, feature = "test-utils"))]
1814    pub(crate) fn assert_invariants(&self) {
1815        assert_eq!(self.by_hash.len(), self.txs.len(), "by_hash.len() != txs.len()");
1816    }
1817}
1818
1819#[cfg(test)]
1820impl<T: PoolTransaction> AllTransactions<T> {
1821    /// This function retrieves the number of transactions stored in the pool for a specific sender.
1822    ///
1823    /// If there are no transactions for the given sender, it returns zero by default.
1824    pub(crate) fn tx_count(&self, sender: SenderId) -> usize {
1825        self.tx_counter.get(&sender).copied().unwrap_or_default()
1826    }
1827}
1828
1829impl<T: PoolTransaction> Default for AllTransactions<T> {
1830    fn default() -> Self {
1831        Self {
1832            max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
1833            minimal_protocol_basefee: MIN_PROTOCOL_BASE_FEE,
1834            block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
1835            by_hash: Default::default(),
1836            txs: Default::default(),
1837            tx_counter: Default::default(),
1838            last_seen_block_number: Default::default(),
1839            last_seen_block_hash: Default::default(),
1840            pending_fees: Default::default(),
1841            price_bumps: Default::default(),
1842            local_transactions_config: Default::default(),
1843            metrics: Default::default(),
1844        }
1845    }
1846}
1847
1848/// Represents updated fees for the pending block.
1849#[derive(Debug, Clone)]
1850pub(crate) struct PendingFees {
1851    /// The pending base fee
1852    pub(crate) base_fee: u64,
1853    /// The pending blob fee
1854    pub(crate) blob_fee: u128,
1855}
1856
1857impl Default for PendingFees {
1858    fn default() -> Self {
1859        Self { base_fee: Default::default(), blob_fee: BLOB_TX_MIN_BLOB_GASPRICE }
1860    }
1861}
1862
1863/// Result type for inserting a transaction
1864pub(crate) type InsertResult<T> = Result<InsertOk<T>, InsertErr<T>>;
1865
1866/// Err variant of `InsertResult`
1867#[derive(Debug)]
1868pub(crate) enum InsertErr<T: PoolTransaction> {
1869    /// Attempted to replace existing transaction, but was underpriced
1870    Underpriced {
1871        transaction: Arc<ValidPoolTransaction<T>>,
1872        #[allow(dead_code)]
1873        existing: TxHash,
1874    },
1875    /// Attempted to insert a blob transaction with a nonce gap
1876    BlobTxHasNonceGap { transaction: Arc<ValidPoolTransaction<T>> },
1877    /// Attempted to insert a transaction that would overdraft the sender's balance at the time of
1878    /// insertion.
1879    Overdraft { transaction: Arc<ValidPoolTransaction<T>> },
1880    /// The transactions feeCap is lower than the chain's minimum fee requirement.
1881    ///
1882    /// See also [`MIN_PROTOCOL_BASE_FEE`]
1883    FeeCapBelowMinimumProtocolFeeCap { transaction: Arc<ValidPoolTransaction<T>>, fee_cap: u128 },
1884    /// Sender currently exceeds the configured limit for max account slots.
1885    ///
1886    /// The sender can be considered a spammer at this point.
1887    ExceededSenderTransactionsCapacity { transaction: Arc<ValidPoolTransaction<T>> },
1888    /// Transaction gas limit exceeds block's gas limit
1889    TxGasLimitMoreThanAvailableBlockGas {
1890        transaction: Arc<ValidPoolTransaction<T>>,
1891        block_gas_limit: u64,
1892        tx_gas_limit: u64,
1893    },
1894    /// Thrown if the mutual exclusivity constraint (blob vs normal transaction) is violated.
1895    TxTypeConflict { transaction: Arc<ValidPoolTransaction<T>> },
1896}
1897
1898/// Transaction was successfully inserted into the pool
1899#[derive(Debug)]
1900pub(crate) struct InsertOk<T: PoolTransaction> {
1901    /// Ref to the inserted transaction.
1902    transaction: Arc<ValidPoolTransaction<T>>,
1903    /// Where to move the transaction to.
1904    move_to: SubPool,
1905    /// Current state of the inserted tx.
1906    #[allow(dead_code)]
1907    state: TxState,
1908    /// The transaction that was replaced by this.
1909    replaced_tx: Option<(Arc<ValidPoolTransaction<T>>, SubPool)>,
1910    /// Additional updates to transactions affected by this change.
1911    updates: Vec<PoolUpdate>,
1912}
1913
1914/// The internal transaction typed used by `AllTransactions` which also additional info used for
1915/// determining the current state of the transaction.
1916#[derive(Debug)]
1917pub(crate) struct PoolInternalTransaction<T: PoolTransaction> {
1918    /// The actual transaction object.
1919    pub(crate) transaction: Arc<ValidPoolTransaction<T>>,
1920    /// The `SubPool` that currently contains this transaction.
1921    pub(crate) subpool: SubPool,
1922    /// Keeps track of the current state of the transaction and therefore in which subpool it
1923    /// should reside
1924    pub(crate) state: TxState,
1925    /// The total cost all transactions before this transaction.
1926    ///
1927    /// This is the combined `cost` of all transactions from the same sender that currently
1928    /// come before this transaction.
1929    pub(crate) cumulative_cost: U256,
1930}
1931
1932// === impl PoolInternalTransaction ===
1933
1934impl<T: PoolTransaction> PoolInternalTransaction<T> {
1935    fn next_cumulative_cost(&self) -> U256 {
1936        self.cumulative_cost + self.transaction.cost()
1937    }
1938}
1939
1940/// Tracks the result after updating the pool
1941#[derive(Debug)]
1942pub(crate) struct UpdateOutcome<T: PoolTransaction> {
1943    /// transactions promoted to the pending pool
1944    pub(crate) promoted: Vec<Arc<ValidPoolTransaction<T>>>,
1945    /// transaction that failed and were discarded
1946    pub(crate) discarded: Vec<Arc<ValidPoolTransaction<T>>>,
1947}
1948
1949impl<T: PoolTransaction> Default for UpdateOutcome<T> {
1950    fn default() -> Self {
1951        Self { promoted: vec![], discarded: vec![] }
1952    }
1953}
1954
1955/// Stores relevant context about a sender.
1956#[derive(Debug, Clone, Default)]
1957pub(crate) struct SenderInfo {
1958    /// current nonce of the sender.
1959    pub(crate) state_nonce: u64,
1960    /// Balance of the sender at the current point.
1961    pub(crate) balance: U256,
1962}
1963
1964// === impl SenderInfo ===
1965
1966impl SenderInfo {
1967    /// Updates the info with the new values.
1968    fn update(&mut self, state_nonce: u64, balance: U256) {
1969        *self = Self { state_nonce, balance };
1970    }
1971}
1972
1973#[cfg(test)]
1974mod tests {
1975    use super::*;
1976    use crate::{
1977        test_utils::{MockOrdering, MockTransaction, MockTransactionFactory, MockTransactionSet},
1978        traits::TransactionOrigin,
1979        SubPoolLimit,
1980    };
1981    use alloy_primitives::address;
1982    use reth_primitives::TxType;
1983
1984    #[test]
1985    fn test_insert_blob() {
1986        let on_chain_balance = U256::MAX;
1987        let on_chain_nonce = 0;
1988        let mut f = MockTransactionFactory::default();
1989        let mut pool = AllTransactions::default();
1990        let tx = MockTransaction::eip4844().inc_price().inc_limit();
1991        let valid_tx = f.validated(tx);
1992        let InsertOk { updates, replaced_tx, move_to, state, .. } =
1993            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
1994        assert!(updates.is_empty());
1995        assert!(replaced_tx.is_none());
1996        assert!(state.contains(TxState::NO_NONCE_GAPS));
1997        assert!(state.contains(TxState::ENOUGH_BALANCE));
1998        assert!(state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
1999        assert_eq!(move_to, SubPool::Pending);
2000
2001        let inserted = pool.txs.get(&valid_tx.transaction_id).unwrap();
2002        assert_eq!(inserted.subpool, SubPool::Pending);
2003    }
2004
2005    #[test]
2006    fn test_insert_blob_not_enough_blob_fee() {
2007        let on_chain_balance = U256::MAX;
2008        let on_chain_nonce = 0;
2009        let mut f = MockTransactionFactory::default();
2010        let mut pool = AllTransactions {
2011            pending_fees: PendingFees { blob_fee: 10_000_000, ..Default::default() },
2012            ..Default::default()
2013        };
2014        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2015        pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap() + 1;
2016        let valid_tx = f.validated(tx);
2017        let InsertOk { state, .. } =
2018            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2019        assert!(state.contains(TxState::NO_NONCE_GAPS));
2020        assert!(!state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2021
2022        let _ = pool.txs.get(&valid_tx.transaction_id).unwrap();
2023    }
2024
2025    #[test]
2026    fn test_valid_tx_with_decreasing_blob_fee() {
2027        let on_chain_balance = U256::MAX;
2028        let on_chain_nonce = 0;
2029        let mut f = MockTransactionFactory::default();
2030        let mut pool = AllTransactions {
2031            pending_fees: PendingFees { blob_fee: 10_000_000, ..Default::default() },
2032            ..Default::default()
2033        };
2034        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2035
2036        pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap() + 1;
2037        let valid_tx = f.validated(tx.clone());
2038        let InsertOk { state, .. } =
2039            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2040        assert!(state.contains(TxState::NO_NONCE_GAPS));
2041        assert!(!state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2042
2043        let _ = pool.txs.get(&valid_tx.transaction_id).unwrap();
2044        pool.remove_transaction(&valid_tx.transaction_id);
2045
2046        pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap();
2047        let InsertOk { state, .. } =
2048            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2049        assert!(state.contains(TxState::NO_NONCE_GAPS));
2050        assert!(state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2051    }
2052
2053    #[test]
2054    fn test_demote_valid_tx_with_increasing_blob_fee() {
2055        let on_chain_balance = U256::MAX;
2056        let on_chain_nonce = 0;
2057        let mut f = MockTransactionFactory::default();
2058        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2059        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2060
2061        // set block info so the tx is initially underpriced w.r.t. blob fee
2062        let mut block_info = pool.block_info();
2063        block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap());
2064        pool.set_block_info(block_info);
2065
2066        let validated = f.validated(tx.clone());
2067        let id = *validated.id();
2068        pool.add_transaction(validated, on_chain_balance, on_chain_nonce).unwrap();
2069
2070        // assert pool lengths
2071        assert!(pool.blob_pool.is_empty());
2072        assert_eq!(pool.pending_pool.len(), 1);
2073
2074        // check tx state and derived subpool
2075        let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2076        assert!(internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2077        assert_eq!(internal_tx.subpool, SubPool::Pending);
2078
2079        // set block info so the pools are updated
2080        block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap() + 1);
2081        pool.set_block_info(block_info);
2082
2083        // check that the tx is promoted
2084        let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2085        assert!(!internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2086        assert_eq!(internal_tx.subpool, SubPool::Blob);
2087
2088        // make sure the blob transaction was promoted into the pending pool
2089        assert_eq!(pool.blob_pool.len(), 1);
2090        assert!(pool.pending_pool.is_empty());
2091    }
2092
2093    #[test]
2094    fn test_promote_valid_tx_with_decreasing_blob_fee() {
2095        let on_chain_balance = U256::MAX;
2096        let on_chain_nonce = 0;
2097        let mut f = MockTransactionFactory::default();
2098        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2099        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2100
2101        // set block info so the tx is initially underpriced w.r.t. blob fee
2102        let mut block_info = pool.block_info();
2103        block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap() + 1);
2104        pool.set_block_info(block_info);
2105
2106        let validated = f.validated(tx.clone());
2107        let id = *validated.id();
2108        pool.add_transaction(validated, on_chain_balance, on_chain_nonce).unwrap();
2109
2110        // assert pool lengths
2111        assert!(pool.pending_pool.is_empty());
2112        assert_eq!(pool.blob_pool.len(), 1);
2113
2114        // check tx state and derived subpool
2115        let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2116        assert!(!internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2117        assert_eq!(internal_tx.subpool, SubPool::Blob);
2118
2119        // set block info so the pools are updated
2120        block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap());
2121        pool.set_block_info(block_info);
2122
2123        // check that the tx is promoted
2124        let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2125        assert!(internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2126        assert_eq!(internal_tx.subpool, SubPool::Pending);
2127
2128        // make sure the blob transaction was promoted into the pending pool
2129        assert_eq!(pool.pending_pool.len(), 1);
2130        assert!(pool.blob_pool.is_empty());
2131    }
2132
2133    /// A struct representing a txpool promotion test instance
2134    #[derive(Debug, PartialEq, Eq, Clone, Hash)]
2135    struct PromotionTest {
2136        /// The basefee at the start of the test
2137        basefee: u64,
2138        /// The blobfee at the start of the test
2139        blobfee: u128,
2140        /// The subpool at the start of the test
2141        subpool: SubPool,
2142        /// The basefee update
2143        basefee_update: u64,
2144        /// The blobfee update
2145        blobfee_update: u128,
2146        /// The subpool after the update
2147        new_subpool: SubPool,
2148    }
2149
2150    impl PromotionTest {
2151        /// Returns the test case for the opposite update
2152        const fn opposite(&self) -> Self {
2153            Self {
2154                basefee: self.basefee_update,
2155                blobfee: self.blobfee_update,
2156                subpool: self.new_subpool,
2157                blobfee_update: self.blobfee,
2158                basefee_update: self.basefee,
2159                new_subpool: self.subpool,
2160            }
2161        }
2162
2163        fn assert_subpool_lengths<T: TransactionOrdering>(
2164            &self,
2165            pool: &TxPool<T>,
2166            failure_message: String,
2167            check_subpool: SubPool,
2168        ) {
2169            match check_subpool {
2170                SubPool::Blob => {
2171                    assert_eq!(pool.blob_pool.len(), 1, "{failure_message}");
2172                    assert!(pool.pending_pool.is_empty(), "{failure_message}");
2173                    assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2174                    assert!(pool.queued_pool.is_empty(), "{failure_message}");
2175                }
2176                SubPool::Pending => {
2177                    assert!(pool.blob_pool.is_empty(), "{failure_message}");
2178                    assert_eq!(pool.pending_pool.len(), 1, "{failure_message}");
2179                    assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2180                    assert!(pool.queued_pool.is_empty(), "{failure_message}");
2181                }
2182                SubPool::BaseFee => {
2183                    assert!(pool.blob_pool.is_empty(), "{failure_message}");
2184                    assert!(pool.pending_pool.is_empty(), "{failure_message}");
2185                    assert_eq!(pool.basefee_pool.len(), 1, "{failure_message}");
2186                    assert!(pool.queued_pool.is_empty(), "{failure_message}");
2187                }
2188                SubPool::Queued => {
2189                    assert!(pool.blob_pool.is_empty(), "{failure_message}");
2190                    assert!(pool.pending_pool.is_empty(), "{failure_message}");
2191                    assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2192                    assert_eq!(pool.queued_pool.len(), 1, "{failure_message}");
2193                }
2194            }
2195        }
2196
2197        /// Runs an assertion on the provided pool, ensuring that the transaction is in the correct
2198        /// subpool based on the starting condition of the test, assuming the pool contains only a
2199        /// single transaction.
2200        fn assert_single_tx_starting_subpool<T: TransactionOrdering>(&self, pool: &TxPool<T>) {
2201            self.assert_subpool_lengths(
2202                pool,
2203                format!("pool length check failed at start of test: {self:?}"),
2204                self.subpool,
2205            );
2206        }
2207
2208        /// Runs an assertion on the provided pool, ensuring that the transaction is in the correct
2209        /// subpool based on the ending condition of the test, assuming the pool contains only a
2210        /// single transaction.
2211        fn assert_single_tx_ending_subpool<T: TransactionOrdering>(&self, pool: &TxPool<T>) {
2212            self.assert_subpool_lengths(
2213                pool,
2214                format!("pool length check failed at end of test: {self:?}"),
2215                self.new_subpool,
2216            );
2217        }
2218    }
2219
2220    #[test]
2221    fn test_promote_blob_tx_with_both_pending_fee_updates() {
2222        // this exhaustively tests all possible promotion scenarios for a single transaction moving
2223        // between the blob and pending pool
2224        let on_chain_balance = U256::MAX;
2225        let on_chain_nonce = 0;
2226        let mut f = MockTransactionFactory::default();
2227        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2228
2229        let max_fee_per_blob_gas = tx.max_fee_per_blob_gas().unwrap();
2230        let max_fee_per_gas = tx.max_fee_per_gas() as u64;
2231
2232        // These are all _promotion_ tests or idempotent tests.
2233        let mut expected_promotions = vec![
2234            PromotionTest {
2235                blobfee: max_fee_per_blob_gas + 1,
2236                basefee: max_fee_per_gas + 1,
2237                subpool: SubPool::Blob,
2238                blobfee_update: max_fee_per_blob_gas + 1,
2239                basefee_update: max_fee_per_gas + 1,
2240                new_subpool: SubPool::Blob,
2241            },
2242            PromotionTest {
2243                blobfee: max_fee_per_blob_gas + 1,
2244                basefee: max_fee_per_gas + 1,
2245                subpool: SubPool::Blob,
2246                blobfee_update: max_fee_per_blob_gas,
2247                basefee_update: max_fee_per_gas + 1,
2248                new_subpool: SubPool::Blob,
2249            },
2250            PromotionTest {
2251                blobfee: max_fee_per_blob_gas + 1,
2252                basefee: max_fee_per_gas + 1,
2253                subpool: SubPool::Blob,
2254                blobfee_update: max_fee_per_blob_gas + 1,
2255                basefee_update: max_fee_per_gas,
2256                new_subpool: SubPool::Blob,
2257            },
2258            PromotionTest {
2259                blobfee: max_fee_per_blob_gas + 1,
2260                basefee: max_fee_per_gas + 1,
2261                subpool: SubPool::Blob,
2262                blobfee_update: max_fee_per_blob_gas,
2263                basefee_update: max_fee_per_gas,
2264                new_subpool: SubPool::Pending,
2265            },
2266            PromotionTest {
2267                blobfee: max_fee_per_blob_gas,
2268                basefee: max_fee_per_gas + 1,
2269                subpool: SubPool::Blob,
2270                blobfee_update: max_fee_per_blob_gas,
2271                basefee_update: max_fee_per_gas,
2272                new_subpool: SubPool::Pending,
2273            },
2274            PromotionTest {
2275                blobfee: max_fee_per_blob_gas + 1,
2276                basefee: max_fee_per_gas,
2277                subpool: SubPool::Blob,
2278                blobfee_update: max_fee_per_blob_gas,
2279                basefee_update: max_fee_per_gas,
2280                new_subpool: SubPool::Pending,
2281            },
2282            PromotionTest {
2283                blobfee: max_fee_per_blob_gas,
2284                basefee: max_fee_per_gas,
2285                subpool: SubPool::Pending,
2286                blobfee_update: max_fee_per_blob_gas,
2287                basefee_update: max_fee_per_gas,
2288                new_subpool: SubPool::Pending,
2289            },
2290        ];
2291
2292        // extend the test cases with reversed updates - this will add all _demotion_ tests
2293        let reversed = expected_promotions.iter().map(|test| test.opposite()).collect::<Vec<_>>();
2294        expected_promotions.extend(reversed);
2295
2296        // dedup the test cases
2297        let expected_promotions = expected_promotions.into_iter().collect::<HashSet<_>>();
2298
2299        for promotion_test in &expected_promotions {
2300            let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2301
2302            // set block info so the tx is initially underpriced w.r.t. blob fee
2303            let mut block_info = pool.block_info();
2304
2305            block_info.pending_blob_fee = Some(promotion_test.blobfee);
2306            block_info.pending_basefee = promotion_test.basefee;
2307            pool.set_block_info(block_info);
2308
2309            let validated = f.validated(tx.clone());
2310            let id = *validated.id();
2311            pool.add_transaction(validated, on_chain_balance, on_chain_nonce).unwrap();
2312
2313            // assert pool lengths
2314            promotion_test.assert_single_tx_starting_subpool(&pool);
2315
2316            // check tx state and derived subpool, it should not move into the blob pool
2317            let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2318            assert_eq!(
2319                internal_tx.subpool, promotion_test.subpool,
2320                "Subpools do not match at start of test: {promotion_test:?}"
2321            );
2322
2323            // set block info with new base fee
2324            block_info.pending_basefee = promotion_test.basefee_update;
2325            block_info.pending_blob_fee = Some(promotion_test.blobfee_update);
2326            pool.set_block_info(block_info);
2327
2328            // check tx state and derived subpool, it should not move into the blob pool
2329            let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2330            assert_eq!(
2331                internal_tx.subpool, promotion_test.new_subpool,
2332                "Subpools do not match at end of test: {promotion_test:?}"
2333            );
2334
2335            // assert new pool lengths
2336            promotion_test.assert_single_tx_ending_subpool(&pool);
2337        }
2338    }
2339
2340    #[test]
2341    fn test_insert_pending() {
2342        let on_chain_balance = U256::MAX;
2343        let on_chain_nonce = 0;
2344        let mut f = MockTransactionFactory::default();
2345        let mut pool = AllTransactions::default();
2346        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2347        let valid_tx = f.validated(tx);
2348        let InsertOk { updates, replaced_tx, move_to, state, .. } =
2349            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2350        assert!(updates.is_empty());
2351        assert!(replaced_tx.is_none());
2352        assert!(state.contains(TxState::NO_NONCE_GAPS));
2353        assert!(state.contains(TxState::ENOUGH_BALANCE));
2354        assert_eq!(move_to, SubPool::Pending);
2355
2356        let inserted = pool.txs.get(&valid_tx.transaction_id).unwrap();
2357        assert_eq!(inserted.subpool, SubPool::Pending);
2358    }
2359
2360    #[test]
2361    fn test_simple_insert() {
2362        let on_chain_balance = U256::ZERO;
2363        let on_chain_nonce = 0;
2364        let mut f = MockTransactionFactory::default();
2365        let mut pool = AllTransactions::default();
2366        let mut tx = MockTransaction::eip1559().inc_price().inc_limit();
2367        tx.set_priority_fee(100);
2368        tx.set_max_fee(100);
2369        let valid_tx = f.validated(tx.clone());
2370        let InsertOk { updates, replaced_tx, move_to, state, .. } =
2371            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2372        assert!(updates.is_empty());
2373        assert!(replaced_tx.is_none());
2374        assert!(state.contains(TxState::NO_NONCE_GAPS));
2375        assert!(!state.contains(TxState::ENOUGH_BALANCE));
2376        assert_eq!(move_to, SubPool::Queued);
2377
2378        assert_eq!(pool.len(), 1);
2379        assert!(pool.contains(valid_tx.hash()));
2380        let expected_state = TxState::ENOUGH_FEE_CAP_BLOCK | TxState::NO_NONCE_GAPS;
2381        let inserted = pool.get(valid_tx.id()).unwrap();
2382        assert!(inserted.state.intersects(expected_state));
2383
2384        // insert the same tx again
2385        let res = pool.insert_tx(valid_tx, on_chain_balance, on_chain_nonce);
2386        res.unwrap_err();
2387        assert_eq!(pool.len(), 1);
2388
2389        let valid_tx = f.validated(tx.next());
2390        let InsertOk { updates, replaced_tx, move_to, state, .. } =
2391            pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2392
2393        assert!(updates.is_empty());
2394        assert!(replaced_tx.is_none());
2395        assert!(state.contains(TxState::NO_NONCE_GAPS));
2396        assert!(!state.contains(TxState::ENOUGH_BALANCE));
2397        assert_eq!(move_to, SubPool::Queued);
2398
2399        assert!(pool.contains(valid_tx.hash()));
2400        assert_eq!(pool.len(), 2);
2401        let inserted = pool.get(valid_tx.id()).unwrap();
2402        assert!(inserted.state.intersects(expected_state));
2403    }
2404
2405    #[test]
2406    fn insert_already_imported() {
2407        let on_chain_balance = U256::ZERO;
2408        let on_chain_nonce = 0;
2409        let mut f = MockTransactionFactory::default();
2410        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2411        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2412        let tx = f.validated(tx);
2413        pool.add_transaction(tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2414        match pool.add_transaction(tx, on_chain_balance, on_chain_nonce).unwrap_err().kind {
2415            PoolErrorKind::AlreadyImported => {}
2416            _ => unreachable!(),
2417        }
2418    }
2419
2420    #[test]
2421    fn insert_replace() {
2422        let on_chain_balance = U256::ZERO;
2423        let on_chain_nonce = 0;
2424        let mut f = MockTransactionFactory::default();
2425        let mut pool = AllTransactions::default();
2426        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2427        let first = f.validated(tx.clone());
2428        let _ = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2429        let replacement = f.validated(tx.rng_hash().inc_price());
2430        let InsertOk { updates, replaced_tx, .. } =
2431            pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap();
2432        assert!(updates.is_empty());
2433        let replaced = replaced_tx.unwrap();
2434        assert_eq!(replaced.0.hash(), first.hash());
2435
2436        // ensure replaced tx is fully removed
2437        assert!(!pool.contains(first.hash()));
2438        assert!(pool.contains(replacement.hash()));
2439        assert_eq!(pool.len(), 1);
2440    }
2441
2442    #[test]
2443    fn insert_replace_txpool() {
2444        let on_chain_balance = U256::ZERO;
2445        let on_chain_nonce = 0;
2446        let mut f = MockTransactionFactory::default();
2447        let mut pool = TxPool::mock();
2448
2449        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2450        let first = f.validated(tx.clone());
2451        let first_added = pool.add_transaction(first, on_chain_balance, on_chain_nonce).unwrap();
2452        let replacement = f.validated(tx.rng_hash().inc_price());
2453        let replacement_added =
2454            pool.add_transaction(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap();
2455
2456        // // ensure replaced tx removed
2457        assert!(!pool.contains(first_added.hash()));
2458        // but the replacement is still there
2459        assert!(pool.subpool_contains(replacement_added.subpool(), replacement_added.id()));
2460
2461        assert!(pool.contains(replacement.hash()));
2462        let size = pool.size();
2463        assert_eq!(size.total, 1);
2464        size.assert_invariants();
2465    }
2466
2467    #[test]
2468    fn insert_replace_underpriced() {
2469        let on_chain_balance = U256::ZERO;
2470        let on_chain_nonce = 0;
2471        let mut f = MockTransactionFactory::default();
2472        let mut pool = AllTransactions::default();
2473        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2474        let first = f.validated(tx.clone());
2475        let _res = pool.insert_tx(first, on_chain_balance, on_chain_nonce);
2476        let mut replacement = f.validated(tx.rng_hash());
2477        replacement.transaction = replacement.transaction.decr_price();
2478        let err = pool.insert_tx(replacement, on_chain_balance, on_chain_nonce).unwrap_err();
2479        assert!(matches!(err, InsertErr::Underpriced { .. }));
2480    }
2481
2482    #[test]
2483    fn insert_replace_underpriced_not_enough_bump() {
2484        let on_chain_balance = U256::ZERO;
2485        let on_chain_nonce = 0;
2486        let mut f = MockTransactionFactory::default();
2487        let mut pool = AllTransactions::default();
2488        let mut tx = MockTransaction::eip1559().inc_price().inc_limit();
2489        tx.set_priority_fee(100);
2490        tx.set_max_fee(100);
2491        let first = f.validated(tx.clone());
2492        let _ = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2493        let mut replacement = f.validated(tx.rng_hash().inc_price());
2494
2495        // a price bump of 9% is not enough for a default min price bump of 10%
2496        replacement.transaction.set_priority_fee(109);
2497        replacement.transaction.set_max_fee(109);
2498        let err =
2499            pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap_err();
2500        assert!(matches!(err, InsertErr::Underpriced { .. }));
2501        // ensure first tx is not removed
2502        assert!(pool.contains(first.hash()));
2503        assert_eq!(pool.len(), 1);
2504
2505        // should also fail if the bump in max fee is not enough
2506        replacement.transaction.set_priority_fee(110);
2507        replacement.transaction.set_max_fee(109);
2508        let err =
2509            pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap_err();
2510        assert!(matches!(err, InsertErr::Underpriced { .. }));
2511        assert!(pool.contains(first.hash()));
2512        assert_eq!(pool.len(), 1);
2513
2514        // should also fail if the bump in priority fee is not enough
2515        replacement.transaction.set_priority_fee(109);
2516        replacement.transaction.set_max_fee(110);
2517        let err = pool.insert_tx(replacement, on_chain_balance, on_chain_nonce).unwrap_err();
2518        assert!(matches!(err, InsertErr::Underpriced { .. }));
2519        assert!(pool.contains(first.hash()));
2520        assert_eq!(pool.len(), 1);
2521    }
2522
2523    #[test]
2524    fn insert_conflicting_type_normal_to_blob() {
2525        let on_chain_balance = U256::from(10_000);
2526        let on_chain_nonce = 0;
2527        let mut f = MockTransactionFactory::default();
2528        let mut pool = AllTransactions::default();
2529        let tx = MockTransaction::eip1559().inc_price().inc_limit();
2530        let first = f.validated(tx.clone());
2531        pool.insert_tx(first, on_chain_balance, on_chain_nonce).unwrap();
2532        let tx = MockTransaction::eip4844().set_sender(tx.sender()).inc_price_by(100).inc_limit();
2533        let blob = f.validated(tx);
2534        let err = pool.insert_tx(blob, on_chain_balance, on_chain_nonce).unwrap_err();
2535        assert!(matches!(err, InsertErr::TxTypeConflict { .. }), "{err:?}");
2536    }
2537
2538    #[test]
2539    fn insert_conflicting_type_blob_to_normal() {
2540        let on_chain_balance = U256::from(10_000);
2541        let on_chain_nonce = 0;
2542        let mut f = MockTransactionFactory::default();
2543        let mut pool = AllTransactions::default();
2544        let tx = MockTransaction::eip4844().inc_price().inc_limit();
2545        let first = f.validated(tx.clone());
2546        pool.insert_tx(first, on_chain_balance, on_chain_nonce).unwrap();
2547        let tx = MockTransaction::eip1559().set_sender(tx.sender()).inc_price_by(100).inc_limit();
2548        let tx = f.validated(tx);
2549        let err = pool.insert_tx(tx, on_chain_balance, on_chain_nonce).unwrap_err();
2550        assert!(matches!(err, InsertErr::TxTypeConflict { .. }), "{err:?}");
2551    }
2552
2553    // insert nonce then nonce - 1
2554    #[test]
2555    fn insert_previous() {
2556        let on_chain_balance = U256::ZERO;
2557        let on_chain_nonce = 0;
2558        let mut f = MockTransactionFactory::default();
2559        let mut pool = AllTransactions::default();
2560        let tx = MockTransaction::eip1559().inc_nonce().inc_price().inc_limit();
2561        let first = f.validated(tx.clone());
2562        let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce);
2563
2564        let first_in_pool = pool.get(first.id()).unwrap();
2565
2566        // has nonce gap
2567        assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2568
2569        let prev = f.validated(tx.prev());
2570        let InsertOk { updates, replaced_tx, state, move_to, .. } =
2571            pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2572
2573        // no updates since still in queued pool
2574        assert!(updates.is_empty());
2575        assert!(replaced_tx.is_none());
2576        assert!(state.contains(TxState::NO_NONCE_GAPS));
2577        assert_eq!(move_to, SubPool::Queued);
2578
2579        let first_in_pool = pool.get(first.id()).unwrap();
2580        // has non nonce gap
2581        assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2582    }
2583
2584    // insert nonce then nonce - 1
2585    #[test]
2586    fn insert_with_updates() {
2587        let on_chain_balance = U256::from(10_000);
2588        let on_chain_nonce = 0;
2589        let mut f = MockTransactionFactory::default();
2590        let mut pool = AllTransactions::default();
2591        let tx = MockTransaction::eip1559().inc_nonce().set_gas_price(100).inc_limit();
2592        let first = f.validated(tx.clone());
2593        let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2594
2595        let first_in_pool = pool.get(first.id()).unwrap();
2596        // has nonce gap
2597        assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2598        assert_eq!(SubPool::Queued, first_in_pool.subpool);
2599
2600        let prev = f.validated(tx.prev());
2601        let InsertOk { updates, replaced_tx, state, move_to, .. } =
2602            pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2603
2604        // updated previous tx
2605        assert_eq!(updates.len(), 1);
2606        assert!(replaced_tx.is_none());
2607        assert!(state.contains(TxState::NO_NONCE_GAPS));
2608        assert_eq!(move_to, SubPool::Pending);
2609
2610        let first_in_pool = pool.get(first.id()).unwrap();
2611        // has non nonce gap
2612        assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2613        assert_eq!(SubPool::Pending, first_in_pool.subpool);
2614    }
2615
2616    #[test]
2617    fn insert_previous_blocking() {
2618        let on_chain_balance = U256::from(1_000);
2619        let on_chain_nonce = 0;
2620        let mut f = MockTransactionFactory::default();
2621        let mut pool = AllTransactions::default();
2622        pool.pending_fees.base_fee = pool.minimal_protocol_basefee.checked_add(1).unwrap();
2623        let tx = MockTransaction::eip1559().inc_nonce().inc_limit();
2624        let first = f.validated(tx.clone());
2625
2626        let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce);
2627
2628        let first_in_pool = pool.get(first.id()).unwrap();
2629
2630        assert!(tx.get_gas_price() < pool.pending_fees.base_fee as u128);
2631        // has nonce gap
2632        assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2633
2634        let prev = f.validated(tx.prev());
2635        let InsertOk { updates, replaced_tx, state, move_to, .. } =
2636            pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2637
2638        assert!(!state.contains(TxState::ENOUGH_FEE_CAP_BLOCK));
2639        // no updates since still in queued pool
2640        assert!(updates.is_empty());
2641        assert!(replaced_tx.is_none());
2642        assert!(state.contains(TxState::NO_NONCE_GAPS));
2643        assert_eq!(move_to, SubPool::BaseFee);
2644
2645        let first_in_pool = pool.get(first.id()).unwrap();
2646        // has non nonce gap
2647        assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2648    }
2649
2650    #[test]
2651    fn rejects_spammer() {
2652        let on_chain_balance = U256::from(1_000);
2653        let on_chain_nonce = 0;
2654        let mut f = MockTransactionFactory::default();
2655        let mut pool = AllTransactions::default();
2656
2657        let mut tx = MockTransaction::eip1559();
2658        let unblocked_tx = tx.clone();
2659        for _ in 0..pool.max_account_slots {
2660            tx = tx.next();
2661            pool.insert_tx(f.validated(tx.clone()), on_chain_balance, on_chain_nonce).unwrap();
2662        }
2663
2664        assert_eq!(
2665            pool.max_account_slots,
2666            pool.tx_count(f.ids.sender_id(tx.get_sender()).unwrap())
2667        );
2668
2669        let err =
2670            pool.insert_tx(f.validated(tx.next()), on_chain_balance, on_chain_nonce).unwrap_err();
2671        assert!(matches!(err, InsertErr::ExceededSenderTransactionsCapacity { .. }));
2672
2673        assert!(pool
2674            .insert_tx(f.validated(unblocked_tx), on_chain_balance, on_chain_nonce)
2675            .is_ok());
2676    }
2677
2678    #[test]
2679    fn allow_local_spamming() {
2680        let on_chain_balance = U256::from(1_000);
2681        let on_chain_nonce = 0;
2682        let mut f = MockTransactionFactory::default();
2683        let mut pool = AllTransactions::default();
2684
2685        let mut tx = MockTransaction::eip1559();
2686        for _ in 0..pool.max_account_slots {
2687            tx = tx.next();
2688            pool.insert_tx(
2689                f.validated_with_origin(TransactionOrigin::Local, tx.clone()),
2690                on_chain_balance,
2691                on_chain_nonce,
2692            )
2693            .unwrap();
2694        }
2695
2696        assert_eq!(
2697            pool.max_account_slots,
2698            pool.tx_count(f.ids.sender_id(tx.get_sender()).unwrap())
2699        );
2700
2701        pool.insert_tx(
2702            f.validated_with_origin(TransactionOrigin::Local, tx.next()),
2703            on_chain_balance,
2704            on_chain_nonce,
2705        )
2706        .unwrap();
2707    }
2708
2709    #[test]
2710    fn reject_tx_over_gas_limit() {
2711        let on_chain_balance = U256::from(1_000);
2712        let on_chain_nonce = 0;
2713        let mut f = MockTransactionFactory::default();
2714        let mut pool = AllTransactions::default();
2715
2716        let tx = MockTransaction::eip1559().with_gas_limit(30_000_001);
2717
2718        assert!(matches!(
2719            pool.insert_tx(f.validated(tx), on_chain_balance, on_chain_nonce),
2720            Err(InsertErr::TxGasLimitMoreThanAvailableBlockGas { .. })
2721        ));
2722    }
2723
2724    #[test]
2725    fn test_tx_equal_gas_limit() {
2726        let on_chain_balance = U256::from(1_000);
2727        let on_chain_nonce = 0;
2728        let mut f = MockTransactionFactory::default();
2729        let mut pool = AllTransactions::default();
2730
2731        let tx = MockTransaction::eip1559().with_gas_limit(30_000_000);
2732
2733        let InsertOk { state, .. } =
2734            pool.insert_tx(f.validated(tx), on_chain_balance, on_chain_nonce).unwrap();
2735        assert!(state.contains(TxState::NOT_TOO_MUCH_GAS));
2736    }
2737
2738    #[test]
2739    fn update_basefee_subpools() {
2740        let mut f = MockTransactionFactory::default();
2741        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2742
2743        let tx = MockTransaction::eip1559().inc_price_by(10);
2744        let validated = f.validated(tx.clone());
2745        let id = *validated.id();
2746        pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2747
2748        assert_eq!(pool.pending_pool.len(), 1);
2749
2750        pool.update_basefee((tx.max_fee_per_gas() + 1) as u64);
2751
2752        assert!(pool.pending_pool.is_empty());
2753        assert_eq!(pool.basefee_pool.len(), 1);
2754
2755        assert_eq!(pool.all_transactions.txs.get(&id).unwrap().subpool, SubPool::BaseFee)
2756    }
2757
2758    #[test]
2759    fn update_basefee_subpools_setting_block_info() {
2760        let mut f = MockTransactionFactory::default();
2761        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2762
2763        let tx = MockTransaction::eip1559().inc_price_by(10);
2764        let validated = f.validated(tx.clone());
2765        let id = *validated.id();
2766        pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2767
2768        assert_eq!(pool.pending_pool.len(), 1);
2769
2770        // use set_block_info for the basefee update
2771        let mut block_info = pool.block_info();
2772        block_info.pending_basefee = (tx.max_fee_per_gas() + 1) as u64;
2773        pool.set_block_info(block_info);
2774
2775        assert!(pool.pending_pool.is_empty());
2776        assert_eq!(pool.basefee_pool.len(), 1);
2777
2778        assert_eq!(pool.all_transactions.txs.get(&id).unwrap().subpool, SubPool::BaseFee)
2779    }
2780
2781    #[test]
2782    fn get_highest_transaction_by_sender_and_nonce() {
2783        // Set up a mock transaction factory and a new transaction pool.
2784        let mut f = MockTransactionFactory::default();
2785        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2786
2787        // Create a mock transaction and add it to the pool.
2788        let tx = MockTransaction::eip1559();
2789        pool.add_transaction(f.validated(tx.clone()), U256::from(1_000), 0).unwrap();
2790
2791        // Create another mock transaction with an incremented price.
2792        let tx1 = tx.inc_price().next();
2793
2794        // Validate the second mock transaction and add it to the pool.
2795        let tx1_validated = f.validated(tx1.clone());
2796        pool.add_transaction(tx1_validated, U256::from(1_000), 0).unwrap();
2797
2798        // Ensure that the calculated next nonce for the sender matches the expected value.
2799        assert_eq!(
2800            pool.get_highest_nonce_by_sender(f.ids.sender_id(&tx.sender()).unwrap()),
2801            Some(1)
2802        );
2803
2804        // Retrieve the highest transaction by sender.
2805        let highest_tx = pool
2806            .get_highest_transaction_by_sender(f.ids.sender_id(&tx.sender()).unwrap())
2807            .expect("Failed to retrieve highest transaction");
2808
2809        // Validate that the retrieved highest transaction matches the expected transaction.
2810        assert_eq!(highest_tx.as_ref().transaction, tx1);
2811    }
2812
2813    #[test]
2814    fn get_highest_consecutive_transaction_by_sender() {
2815        // Set up a mock transaction factory and a new transaction pool.
2816        let mut pool = TxPool::new(MockOrdering::default(), PoolConfig::default());
2817        let mut f = MockTransactionFactory::default();
2818
2819        // Create transactions with nonces 0, 1, 2, 4, 5.
2820        let sender = Address::random();
2821        let txs: Vec<_> = vec![0, 1, 2, 4, 5, 8, 9];
2822        for nonce in txs {
2823            let mut mock_tx = MockTransaction::eip1559();
2824            mock_tx.set_sender(sender);
2825            mock_tx.set_nonce(nonce);
2826
2827            let validated_tx = f.validated(mock_tx);
2828            pool.add_transaction(validated_tx, U256::from(1000), 0).unwrap();
2829        }
2830
2831        // Get last consecutive transaction
2832        let sender_id = f.ids.sender_id(&sender).unwrap();
2833        let next_tx =
2834            pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(0));
2835        assert_eq!(next_tx.map(|tx| tx.nonce()), Some(2), "Expected nonce 2 for on-chain nonce 0");
2836
2837        let next_tx =
2838            pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(4));
2839        assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 4");
2840
2841        let next_tx =
2842            pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5));
2843        assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 5");
2844
2845        // update the tracked nonce
2846        let mut info = SenderInfo::default();
2847        info.update(8, U256::ZERO);
2848        pool.sender_info.insert(sender_id, info);
2849        let next_tx =
2850            pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5));
2851        assert_eq!(next_tx.map(|tx| tx.nonce()), Some(9), "Expected nonce 9 for on-chain nonce 8");
2852    }
2853
2854    #[test]
2855    fn discard_nonce_too_low() {
2856        let mut f = MockTransactionFactory::default();
2857        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2858
2859        let tx = MockTransaction::eip1559().inc_price_by(10);
2860        let validated = f.validated(tx.clone());
2861        let id = *validated.id();
2862        pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2863
2864        let next = tx.next();
2865        let validated = f.validated(next.clone());
2866        pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2867
2868        assert_eq!(pool.pending_pool.len(), 2);
2869
2870        let mut changed_senders = HashMap::default();
2871        changed_senders.insert(
2872            id.sender,
2873            SenderInfo { state_nonce: next.nonce(), balance: U256::from(1_000) },
2874        );
2875        let outcome = pool.update_accounts(changed_senders);
2876        assert_eq!(outcome.discarded.len(), 1);
2877        assert_eq!(pool.pending_pool.len(), 1);
2878    }
2879
2880    #[test]
2881    fn discard_with_large_blob_txs() {
2882        // init tracing
2883        reth_tracing::init_test_tracing();
2884
2885        // this test adds large txs to the parked pool, then attempting to discard worst
2886        let mut f = MockTransactionFactory::default();
2887        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2888        let default_limits = pool.config.blob_limit;
2889
2890        // create a chain of transactions by sender A
2891        // make sure they are all one over half the limit
2892        let a_sender = address!("000000000000000000000000000000000000000a");
2893
2894        // set the base fee of the pool
2895        let mut block_info = pool.block_info();
2896        block_info.pending_blob_fee = Some(100);
2897        block_info.pending_basefee = 100;
2898
2899        // update
2900        pool.set_block_info(block_info);
2901
2902        // 2 txs, that should put the pool over the size limit but not max txs
2903        let a_txs = MockTransactionSet::dependent(a_sender, 0, 2, TxType::Eip4844)
2904            .into_iter()
2905            .map(|mut tx| {
2906                tx.set_size(default_limits.max_size / 2 + 1);
2907                tx.set_max_fee((block_info.pending_basefee - 1).into());
2908                tx
2909            })
2910            .collect::<Vec<_>>();
2911
2912        // add all the transactions to the parked pool
2913        for tx in a_txs {
2914            pool.add_transaction(f.validated(tx), U256::from(1_000), 0).unwrap();
2915        }
2916
2917        // truncate the pool, it should remove at least one transaction
2918        let removed = pool.discard_worst();
2919        assert_eq!(removed.len(), 1);
2920    }
2921
2922    #[test]
2923    fn discard_with_parked_large_txs() {
2924        // init tracing
2925        reth_tracing::init_test_tracing();
2926
2927        // this test adds large txs to the parked pool, then attempting to discard worst
2928        let mut f = MockTransactionFactory::default();
2929        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2930        let default_limits = pool.config.queued_limit;
2931
2932        // create a chain of transactions by sender A
2933        // make sure they are all one over half the limit
2934        let a_sender = address!("000000000000000000000000000000000000000a");
2935
2936        // set the base fee of the pool
2937        let pool_base_fee = 100;
2938        pool.update_basefee(pool_base_fee);
2939
2940        // 2 txs, that should put the pool over the size limit but not max txs
2941        let a_txs = MockTransactionSet::dependent(a_sender, 0, 3, TxType::Eip1559)
2942            .into_iter()
2943            .map(|mut tx| {
2944                tx.set_size(default_limits.max_size / 2 + 1);
2945                tx.set_max_fee((pool_base_fee - 1).into());
2946                tx
2947            })
2948            .collect::<Vec<_>>();
2949
2950        // add all the transactions to the parked pool
2951        for tx in a_txs {
2952            pool.add_transaction(f.validated(tx), U256::from(1_000), 0).unwrap();
2953        }
2954
2955        // truncate the pool, it should remove at least one transaction
2956        let removed = pool.discard_worst();
2957        assert_eq!(removed.len(), 1);
2958    }
2959
2960    #[test]
2961    fn discard_at_capacity() {
2962        let mut f = MockTransactionFactory::default();
2963        let queued_limit = SubPoolLimit::new(1000, usize::MAX);
2964        let mut pool =
2965            TxPool::new(MockOrdering::default(), PoolConfig { queued_limit, ..Default::default() });
2966
2967        // insert a bunch of transactions into the queued pool
2968        for _ in 0..queued_limit.max_txs {
2969            let tx = MockTransaction::eip1559().inc_price_by(10).inc_nonce();
2970            let validated = f.validated(tx.clone());
2971            let _id = *validated.id();
2972            pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2973        }
2974
2975        let size = pool.size();
2976        assert_eq!(size.queued, queued_limit.max_txs);
2977
2978        for _ in 0..queued_limit.max_txs {
2979            let tx = MockTransaction::eip1559().inc_price_by(10).inc_nonce();
2980            let validated = f.validated(tx.clone());
2981            let _id = *validated.id();
2982            pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
2983
2984            pool.discard_worst();
2985            pool.assert_invariants();
2986            assert!(pool.size().queued <= queued_limit.max_txs);
2987        }
2988    }
2989
2990    #[test]
2991    fn discard_blobs_at_capacity() {
2992        let mut f = MockTransactionFactory::default();
2993        let blob_limit = SubPoolLimit::new(1000, usize::MAX);
2994        let mut pool =
2995            TxPool::new(MockOrdering::default(), PoolConfig { blob_limit, ..Default::default() });
2996        pool.all_transactions.pending_fees.blob_fee = 10000;
2997        // insert a bunch of transactions into the queued pool
2998        for _ in 0..blob_limit.max_txs {
2999            let tx = MockTransaction::eip4844().inc_price_by(100).with_blob_fee(100);
3000            let validated = f.validated(tx.clone());
3001            let _id = *validated.id();
3002            pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
3003        }
3004
3005        let size = pool.size();
3006        assert_eq!(size.blob, blob_limit.max_txs);
3007
3008        for _ in 0..blob_limit.max_txs {
3009            let tx = MockTransaction::eip4844().inc_price_by(100).with_blob_fee(100);
3010            let validated = f.validated(tx.clone());
3011            let _id = *validated.id();
3012            pool.add_transaction(validated, U256::from(1_000), 0).unwrap();
3013
3014            pool.discard_worst();
3015            pool.assert_invariants();
3016            assert!(pool.size().blob <= blob_limit.max_txs);
3017        }
3018    }
3019
3020    #[test]
3021    fn account_updates_nonce_gap() {
3022        let on_chain_balance = U256::from(10_000);
3023        let mut on_chain_nonce = 0;
3024        let mut f = MockTransactionFactory::default();
3025        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3026
3027        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3028        let tx_1 = tx_0.next();
3029        let tx_2 = tx_1.next();
3030
3031        // Create 4 transactions
3032        let v0 = f.validated(tx_0);
3033        let v1 = f.validated(tx_1);
3034        let v2 = f.validated(tx_2);
3035
3036        // Add first 2 to the pool
3037        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3038        let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce).unwrap();
3039
3040        assert!(pool.queued_transactions().is_empty());
3041        assert_eq!(2, pool.pending_transactions().len());
3042
3043        // Remove first (nonce 0) - simulating that it was taken to be a part of the block.
3044        pool.prune_transaction_by_hash(v0.hash());
3045
3046        // Now add transaction with nonce 2
3047        let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce).unwrap();
3048
3049        // v2 is in the queue now. v1 is still in 'pending'.
3050        assert_eq!(1, pool.queued_transactions().len());
3051        assert_eq!(1, pool.pending_transactions().len());
3052
3053        // Simulate new block arrival - and chain nonce increasing.
3054        let mut updated_accounts = HashMap::default();
3055        on_chain_nonce += 1;
3056        updated_accounts.insert(
3057            v0.sender_id(),
3058            SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
3059        );
3060        pool.update_accounts(updated_accounts);
3061
3062        // 'pending' now).
3063        assert!(pool.queued_transactions().is_empty());
3064        assert_eq!(2, pool.pending_transactions().len());
3065    }
3066    #[test]
3067    fn test_transaction_removal() {
3068        let on_chain_balance = U256::from(10_000);
3069        let on_chain_nonce = 0;
3070        let mut f = MockTransactionFactory::default();
3071        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3072
3073        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3074        let tx_1 = tx_0.next();
3075
3076        // Create 2 transactions
3077        let v0 = f.validated(tx_0);
3078        let v1 = f.validated(tx_1);
3079
3080        // Add them to the pool
3081        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3082        let _res = pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce).unwrap();
3083
3084        assert_eq!(0, pool.queued_transactions().len());
3085        assert_eq!(2, pool.pending_transactions().len());
3086
3087        // Remove first (nonce 0) - simulating that it was taken to be a part of the block.
3088        pool.remove_transaction(v0.id());
3089        // assert the second transaction is really at the top of the queue
3090        let pool_txs = pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>();
3091        assert_eq!(vec![v1.nonce()], pool_txs);
3092    }
3093    #[test]
3094    fn test_remove_transactions() {
3095        let on_chain_balance = U256::from(10_000);
3096        let on_chain_nonce = 0;
3097        let mut f = MockTransactionFactory::default();
3098        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3099
3100        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3101        let tx_1 = tx_0.next();
3102        let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3103        let tx_3 = tx_2.next();
3104
3105        // Create 4 transactions
3106        let v0 = f.validated(tx_0);
3107        let v1 = f.validated(tx_1);
3108        let v2 = f.validated(tx_2);
3109        let v3 = f.validated(tx_3);
3110
3111        // Add them to the pool
3112        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3113        let _res = pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce).unwrap();
3114        let _res = pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce).unwrap();
3115        let _res = pool.add_transaction(v3.clone(), on_chain_balance, on_chain_nonce).unwrap();
3116
3117        assert_eq!(0, pool.queued_transactions().len());
3118        assert_eq!(4, pool.pending_transactions().len());
3119
3120        pool.remove_transactions(vec![*v0.hash(), *v2.hash()]);
3121
3122        assert_eq!(0, pool.queued_transactions().len());
3123        assert_eq!(2, pool.pending_transactions().len());
3124        assert!(pool.contains(v1.hash()));
3125        assert!(pool.contains(v3.hash()));
3126    }
3127
3128    #[test]
3129    fn test_remove_transactions_and_descendants() {
3130        let on_chain_balance = U256::from(10_000);
3131        let on_chain_nonce = 0;
3132        let mut f = MockTransactionFactory::default();
3133        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3134
3135        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3136        let tx_1 = tx_0.next();
3137        let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3138        let tx_3 = tx_2.next();
3139        let tx_4 = tx_3.next();
3140
3141        // Create 5 transactions
3142        let v0 = f.validated(tx_0);
3143        let v1 = f.validated(tx_1);
3144        let v2 = f.validated(tx_2);
3145        let v3 = f.validated(tx_3);
3146        let v4 = f.validated(tx_4);
3147
3148        // Add them to the pool
3149        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3150        let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce).unwrap();
3151        let _res = pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce).unwrap();
3152        let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce).unwrap();
3153        let _res = pool.add_transaction(v4, on_chain_balance, on_chain_nonce).unwrap();
3154
3155        assert_eq!(0, pool.queued_transactions().len());
3156        assert_eq!(5, pool.pending_transactions().len());
3157
3158        pool.remove_transactions_and_descendants(vec![*v0.hash(), *v2.hash()]);
3159
3160        assert_eq!(0, pool.queued_transactions().len());
3161        assert_eq!(0, pool.pending_transactions().len());
3162    }
3163    #[test]
3164    fn test_remove_descendants() {
3165        let on_chain_balance = U256::from(10_000);
3166        let on_chain_nonce = 0;
3167        let mut f = MockTransactionFactory::default();
3168        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3169
3170        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3171        let tx_1 = tx_0.next();
3172        let tx_2 = tx_1.next();
3173        let tx_3 = tx_2.next();
3174
3175        // Create 4 transactions
3176        let v0 = f.validated(tx_0);
3177        let v1 = f.validated(tx_1);
3178        let v2 = f.validated(tx_2);
3179        let v3 = f.validated(tx_3);
3180
3181        // Add them to the pool
3182        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3183        let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce).unwrap();
3184        let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce).unwrap();
3185        let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce).unwrap();
3186
3187        assert_eq!(0, pool.queued_transactions().len());
3188        assert_eq!(4, pool.pending_transactions().len());
3189
3190        let mut removed = Vec::new();
3191        pool.remove_transaction(v0.id());
3192        pool.remove_descendants(v0.id(), &mut removed);
3193
3194        assert_eq!(0, pool.queued_transactions().len());
3195        assert_eq!(0, pool.pending_transactions().len());
3196        assert_eq!(3, removed.len());
3197    }
3198    #[test]
3199    fn test_remove_transactions_by_sender() {
3200        let on_chain_balance = U256::from(10_000);
3201        let on_chain_nonce = 0;
3202        let mut f = MockTransactionFactory::default();
3203        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3204
3205        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3206        let tx_1 = tx_0.next();
3207        let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3208        let tx_3 = tx_2.next();
3209        let tx_4 = tx_3.next();
3210
3211        // Create 5 transactions
3212        let v0 = f.validated(tx_0);
3213        let v1 = f.validated(tx_1);
3214        let v2 = f.validated(tx_2);
3215        let v3 = f.validated(tx_3);
3216        let v4 = f.validated(tx_4);
3217
3218        // Add them to the pool
3219        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3220        let _res = pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce).unwrap();
3221        let _res = pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce).unwrap();
3222        let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce).unwrap();
3223        let _res = pool.add_transaction(v4, on_chain_balance, on_chain_nonce).unwrap();
3224
3225        assert_eq!(0, pool.queued_transactions().len());
3226        assert_eq!(5, pool.pending_transactions().len());
3227
3228        pool.remove_transactions_by_sender(v2.sender_id());
3229
3230        assert_eq!(0, pool.queued_transactions().len());
3231        assert_eq!(2, pool.pending_transactions().len());
3232        assert!(pool.contains(v0.hash()));
3233        assert!(pool.contains(v1.hash()));
3234    }
3235    #[test]
3236    fn wrong_best_order_of_transactions() {
3237        let on_chain_balance = U256::from(10_000);
3238        let mut on_chain_nonce = 0;
3239        let mut f = MockTransactionFactory::default();
3240        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3241
3242        let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3243        let tx_1 = tx_0.next();
3244        let tx_2 = tx_1.next();
3245        let tx_3 = tx_2.next();
3246
3247        // Create 4 transactions
3248        let v0 = f.validated(tx_0);
3249        let v1 = f.validated(tx_1);
3250        let v2 = f.validated(tx_2);
3251        let v3 = f.validated(tx_3);
3252
3253        // Add first 2 to the pool
3254        let _res = pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce).unwrap();
3255        let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce).unwrap();
3256
3257        assert_eq!(0, pool.queued_transactions().len());
3258        assert_eq!(2, pool.pending_transactions().len());
3259
3260        // Remove first (nonce 0) - simulating that it was taken to be a part of the block.
3261        pool.remove_transaction(v0.id());
3262
3263        // Now add transaction with nonce 2
3264        let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce).unwrap();
3265
3266        // v2 is in the queue now. v1 is still in 'pending'.
3267        assert_eq!(1, pool.queued_transactions().len());
3268        assert_eq!(1, pool.pending_transactions().len());
3269
3270        // Simulate new block arrival - and chain nonce increasing.
3271        let mut updated_accounts = HashMap::default();
3272        on_chain_nonce += 1;
3273        updated_accounts.insert(
3274            v0.sender_id(),
3275            SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
3276        );
3277        pool.update_accounts(updated_accounts);
3278
3279        // Transactions are not changed (IMHO - this is a bug, as transaction v2 should be in the
3280        // 'pending' now).
3281        assert_eq!(0, pool.queued_transactions().len());
3282        assert_eq!(2, pool.pending_transactions().len());
3283
3284        // Add transaction v3 - it 'unclogs' everything.
3285        let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce).unwrap();
3286        assert_eq!(0, pool.queued_transactions().len());
3287        assert_eq!(3, pool.pending_transactions().len());
3288
3289        // It should have returned transactions in order (v1, v2, v3 - as there is nothing blocking
3290        // them).
3291        assert_eq!(
3292            pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>(),
3293            vec![1, 2, 3]
3294        );
3295    }
3296
3297    #[test]
3298    fn test_pending_ordering() {
3299        let mut f = MockTransactionFactory::default();
3300        let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3301
3302        let tx_0 = MockTransaction::eip1559().with_nonce(1).set_gas_price(100).inc_limit();
3303        let tx_1 = tx_0.next();
3304
3305        let v0 = f.validated(tx_0);
3306        let v1 = f.validated(tx_1);
3307
3308        // nonce gap, tx should be queued
3309        pool.add_transaction(v0.clone(), U256::MAX, 0).unwrap();
3310        assert_eq!(1, pool.queued_transactions().len());
3311
3312        // nonce gap is closed on-chain, both transactions should be moved to pending
3313        pool.add_transaction(v1, U256::MAX, 1).unwrap();
3314
3315        assert_eq!(2, pool.pending_transactions().len());
3316        assert_eq!(0, pool.queued_transactions().len());
3317
3318        assert_eq!(
3319            pool.pending_pool.independent().get(&v0.sender_id()).unwrap().transaction.nonce(),
3320            v0.nonce()
3321        );
3322    }
3323
3324    // <https://github.com/paradigmxyz/reth/issues/12286>
3325    #[test]
3326    fn one_sender_one_independent_transaction() {
3327        let mut on_chain_balance = U256::from(4_999); // only enough for 4 txs
3328        let mut on_chain_nonce = 40;
3329        let mut f = MockTransactionFactory::default();
3330        let mut pool = TxPool::mock();
3331        let mut submitted_txs = Vec::new();
3332
3333        // We use a "template" because we want all txs to have the same sender.
3334        let template =
3335            MockTransaction::eip1559().inc_price().inc_limit().with_value(U256::from(1_001));
3336
3337        // Add 8 txs. Because the balance is only sufficient for 4, so the last 4 will be
3338        // Queued.
3339        for tx_nonce in 40..48 {
3340            let tx = f.validated(template.clone().with_nonce(tx_nonce).rng_hash());
3341            submitted_txs.push(*tx.id());
3342            pool.add_transaction(tx, on_chain_balance, on_chain_nonce).unwrap();
3343        }
3344
3345        // A block is mined with two txs (so nonce is changed from 40 to 42).
3346        // Now the balance gets so high that it's enough to execute alltxs.
3347        on_chain_balance = U256::from(999_999);
3348        on_chain_nonce = 42;
3349        pool.remove_transaction(&submitted_txs[0]);
3350        pool.remove_transaction(&submitted_txs[1]);
3351
3352        // Add 4 txs.
3353        for tx_nonce in 48..52 {
3354            pool.add_transaction(
3355                f.validated(template.clone().with_nonce(tx_nonce).rng_hash()),
3356                on_chain_balance,
3357                on_chain_nonce,
3358            )
3359            .unwrap();
3360        }
3361
3362        let best_txs: Vec<_> = pool.pending().best().map(|tx| *tx.id()).collect();
3363        assert_eq!(best_txs.len(), 10); // 8 - 2 + 4 = 10
3364
3365        assert_eq!(pool.pending_pool.independent().len(), 1);
3366    }
3367}