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