1use 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)]
43pub struct TxPool<T: TransactionOrdering> {
85 sender_info: FxHashMap<SenderId, SenderInfo>,
87 pending_pool: PendingPool<T>,
91 config: PoolConfig,
93 queued_pool: ParkedPool<QueuedOrd<T::Transaction>>,
100 basefee_pool: ParkedPool<BasefeeOrd<T::Transaction>>,
105 blob_pool: BlobTransactions<T::Transaction>,
112 all_transactions: AllTransactions<T::Transaction>,
114 metrics: TxPoolMetrics,
116 latest_update_kind: Option<PoolUpdateKind>,
118}
119
120impl<T: TransactionOrdering> TxPool<T> {
123 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 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 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 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 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 pub(crate) const fn all(&self) -> &AllTransactions<T::Transaction> {
183 &self.all_transactions
184 }
185
186 pub(crate) fn unique_senders(&self) -> HashSet<Address> {
188 self.all_transactions.txs.values().map(|tx| tx.transaction.sender()).collect()
189 }
190
191 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 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 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 }
225 (Ordering::Greater, Ordering::Equal | Ordering::Greater) => {
226 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 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 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 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 Ordering::Equal
271 }
272 Ordering::Greater => {
273 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 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 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 pub(crate) fn best_transactions(&self) -> BestTransactions<T> {
334 self.pending_pool.best()
335 }
336
337 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 match best_transactions_attributes.basefee.cmp(&self.all_transactions.pending_fees.base_fee)
351 {
352 Ordering::Equal => {
353 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 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 let mut unlocked = self
382 .basefee_pool
383 .satisfy_base_fee_transactions(best_transactions_attributes.basefee);
384
385 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 pub(crate) fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
398 self.pending_pool.all().collect()
399 }
400 pub(crate) fn pending_transactions_iter(
402 &self,
403 ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
404 self.pending_pool.all()
405 }
406
407 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 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 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 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 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 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 pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
453 self.all_transactions.contains(tx_hash)
454 }
455
456 #[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 #[inline]
469 pub(crate) fn is_exceeded(&self) -> bool {
470 self.config.is_exceeded(self.size())
471 }
472
473 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 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 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 pub(crate) fn update_accounts(
499 &mut self,
500 changed_senders: FxHashMap<SenderId, SenderInfo>,
501 ) -> UpdateOutcome<T::Transaction> {
502 let updates = self.all_transactions.update(&changed_senders);
504
505 self.sender_info.extend(changed_senders);
507
508 let update = self.process_updates(updates);
510 self.update_size_metrics();
512 update
513 }
514
515 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 let block_hash = block_info.last_seen_block_hash;
528 self.all_transactions.set_block_info(block_info);
529
530 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 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 self.latest_update_kind = Some(update_kind);
548
549 OnNewCanonicalStateOutcome { block_hash, mined: mined_transactions, promoted, discarded }
550 }
551
552 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 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 _ => {} }
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 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 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 self.add_new_transaction(transaction.clone(), replaced_tx.clone(), move_to);
637 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 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 self.update_size_metrics();
657
658 Ok(res)
659 }
660 Err(err) => {
661 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 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 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, ¤t, "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 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 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 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 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 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 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 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 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 trace!(target: "txpool", hash=%tx.transaction.hash(), ?pool, "Removed transaction from a subpool");
863 }
864
865 tx
866 }
867
868 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 trace!(target: "txpool", hash=%tx.transaction.hash(), ?pool, "Pruned transaction from a subpool");
887 }
888
889 tx
890 }
891
892 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 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 fn add_transaction_to_subpool(
919 &mut self,
920 pool: SubPool,
921 tx: Arc<ValidPoolTransaction<T::Transaction>>,
922 ) {
923 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 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 self.remove_from_subpool(replaced_pool, replaced.id());
948 }
949
950 self.add_transaction_to_subpool(pool, transaction)
951 }
952
953 pub(crate) fn discard_worst(&mut self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
960 let mut removed = Vec::new();
961
962 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 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 for tx in removed_from_subpool {
993 $this.all_transactions.remove_transaction(tx.id());
994
995 let id = *tx.id();
996
997 removed.push(tx);
999
1000 $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 pub(crate) fn len(&self) -> usize {
1023 self.all_transactions.len()
1024 }
1025
1026 pub(crate) fn is_empty(&self) -> bool {
1028 self.all_transactions.is_empty()
1029 }
1030
1031 #[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 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#[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
1089pub(crate) struct AllTransactions<T: PoolTransaction> {
1094 minimal_protocol_basefee: u64,
1098 block_gas_limit: u64,
1100 max_account_slots: usize,
1102 by_hash: HashMap<TxHash, Arc<ValidPoolTransaction<T>>>,
1104 txs: BTreeMap<TransactionId, PoolInternalTransaction<T>>,
1106 tx_counter: FxHashMap<SenderId, usize>,
1108 last_seen_block_number: u64,
1110 last_seen_block_hash: B256,
1112 pending_fees: PendingFees,
1114 price_bumps: PriceBumpConfig,
1116 local_transactions_config: LocalTransactionConfig,
1118 metrics: AllTransactionsMetrics,
1120}
1121
1122impl<T: PoolTransaction> AllTransactions<T> {
1123 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 #[allow(dead_code)]
1137 pub(crate) fn hashes_iter(&self) -> impl Iterator<Item = TxHash> + '_ {
1138 self.by_hash.keys().copied()
1139 }
1140
1141 pub(crate) fn transactions_iter(
1143 &self,
1144 ) -> impl Iterator<Item = &Arc<ValidPoolTransaction<T>>> + '_ {
1145 self.by_hash.values()
1146 }
1147
1148 pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
1150 self.by_hash.contains_key(tx_hash)
1151 }
1152
1153 pub(crate) fn get(&self, id: &TransactionId) -> Option<&PoolInternalTransaction<T>> {
1155 self.txs.get(id)
1156 }
1157
1158 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 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 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 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 pub(crate) fn update(
1225 &mut self,
1226 changed_accounts: &FxHashMap<SenderId, SenderInfo>,
1227 ) -> Vec<PoolUpdate> {
1228 let mut updates = Vec::with_capacity(64);
1230
1231 let mut iter = self.txs.iter_mut().peekable();
1232
1233 '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 let mut changed_balance = None;
1255
1256 if let Some(info) = changed_accounts.get(&id.sender) {
1258 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 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 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 tx.state.has_nonce_gap() {
1288 next_sender!(iter);
1289 continue 'transactions
1290 }
1291
1292 tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1294
1295 Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1297 Self::record_subpool_update(&mut updates, tx);
1299
1300 let mut has_parked_ancestor = !tx.state.is_pending();
1302
1303 let mut cumulative_cost = tx.next_cumulative_cost();
1304
1305 let mut next_nonce_in_line = tx.transaction.nonce().saturating_add(1);
1307
1308 while let Some((peek, ref mut tx)) = iter.peek_mut() {
1310 if peek.sender != id.sender {
1311 continue 'transactions
1313 }
1314
1315 if tx.transaction.nonce() == next_nonce_in_line {
1316 tx.state.insert(TxState::NO_NONCE_GAPS);
1318 } else {
1319 next_sender!(iter);
1321 continue 'transactions
1322 }
1323
1324 next_nonce_in_line = next_nonce_in_line.saturating_add(1);
1326
1327 tx.cumulative_cost = cumulative_cost;
1329 cumulative_cost = tx.next_cumulative_cost();
1331
1332 if let Some(changed_balance) = changed_balance {
1334 if &cumulative_cost > changed_balance {
1335 tx.state.remove(TxState::ENOUGH_BALANCE);
1337 } else {
1338 tx.state.insert(TxState::ENOUGH_BALANCE);
1339 }
1340 }
1341
1342 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 Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1352 Self::record_subpool_update(&mut updates, tx);
1353
1354 iter.next();
1356 }
1357 }
1358
1359 updates
1360 }
1361
1362 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 fn update_tx_base_fee(pending_block_base_fee: u64, tx: &mut PoolInternalTransaction<T>) {
1381 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 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 #[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 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 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 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 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 self.tx_decr(tx.sender_id());
1457 self.update_size_metrics();
1458 Some((tx, internal.subpool))
1459 }
1460
1461 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 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 #[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 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 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 return Err(InsertErr::TxTypeConflict { transaction: Arc::new(transaction) })
1531 }
1532
1533 Ok(transaction)
1534 }
1535
1536 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 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 self.metrics.blob_transactions_nonce_gaps.increment(1);
1557 return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
1558 }
1559
1560 let mut cumulative_cost = ancestor_tx.next_cumulative_cost() + new_blob_tx.cost();
1562
1563 if cumulative_cost > on_chain_balance {
1565 return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1567 }
1568
1569 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 descendants.next();
1577
1578 for (_, tx) in descendants {
1580 cumulative_cost += tx.transaction.cost();
1581 if tx.transaction.is_eip4844() && cumulative_cost > on_chain_balance {
1582 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 return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1591 }
1592
1593 Ok(new_blob_tx)
1594 }
1595
1596 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 state.insert(TxState::NOT_TOO_MUCH_GAS);
1644
1645 let ancestor = TransactionId::ancestor(
1648 transaction.transaction.nonce(),
1649 on_chain_nonce,
1650 inserted_tx_id.sender,
1651 );
1652
1653 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 state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
1667 }
1668
1669 let transaction = Arc::new(transaction);
1670
1671 if ancestor.is_none() {
1673 state.insert(TxState::NO_NONCE_GAPS);
1674 state.insert(TxState::NO_PARKED_ANCESTORS);
1675 }
1676
1677 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 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 match self.txs.entry(*transaction.id()) {
1699 Entry::Vacant(entry) => {
1700 self.by_hash.insert(*pool_tx.transaction.hash(), pool_tx.transaction.clone());
1702 entry.insert(pool_tx);
1703 }
1704 Entry::Occupied(mut entry) => {
1705 let existing_transaction = entry.get().transaction.as_ref();
1707 let maybe_replacement = transaction.as_ref();
1708
1709 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 replaced_tx = Some((replaced.transaction, replaced.subpool));
1723 }
1724 }
1725
1726 let on_chain_id = TransactionId::new(transaction.sender_id(), on_chain_nonce);
1728 {
1729 let mut next_nonce = on_chain_id.nonce;
1731
1732 let mut has_parked_ancestor = false;
1736
1737 for (id, tx) in self.descendant_txs_mut(&on_chain_id) {
1740 let current_pool = tx.subpool;
1741
1742 if next_nonce != id.nonce {
1744 break
1745 }
1746
1747 tx.state.insert(TxState::NO_NONCE_GAPS);
1749
1750 tx.cumulative_cost = cumulative_cost;
1752
1753 cumulative_cost = tx.next_cumulative_cost();
1755
1756 if cumulative_cost > on_chain_balance {
1757 tx.state.remove(TxState::ENOUGH_BALANCE);
1759 } else {
1760 tx.state.insert(TxState::ENOUGH_BALANCE);
1761 }
1762
1763 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 tx.subpool = tx.state.into();
1773
1774 if inserted_tx_id.eq(id) {
1775 state = tx.state;
1777 } else {
1778 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 next_nonce = id.next_nonce();
1791 }
1792 }
1793
1794 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 pub(crate) fn len(&self) -> usize {
1806 self.txs.len()
1807 }
1808
1809 pub(crate) fn is_empty(&self) -> bool {
1811 self.txs.is_empty()
1812 }
1813
1814 #[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 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#[derive(Debug, Clone)]
1852pub(crate) struct PendingFees {
1853 pub(crate) base_fee: u64,
1855 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
1865pub(crate) type InsertResult<T> = Result<InsertOk<T>, InsertErr<T>>;
1867
1868#[derive(Debug)]
1870pub(crate) enum InsertErr<T: PoolTransaction> {
1871 Underpriced {
1873 transaction: Arc<ValidPoolTransaction<T>>,
1874 #[allow(dead_code)]
1875 existing: TxHash,
1876 },
1877 BlobTxHasNonceGap { transaction: Arc<ValidPoolTransaction<T>> },
1879 Overdraft { transaction: Arc<ValidPoolTransaction<T>> },
1882 FeeCapBelowMinimumProtocolFeeCap { transaction: Arc<ValidPoolTransaction<T>>, fee_cap: u128 },
1886 ExceededSenderTransactionsCapacity { transaction: Arc<ValidPoolTransaction<T>> },
1890 TxGasLimitMoreThanAvailableBlockGas {
1892 transaction: Arc<ValidPoolTransaction<T>>,
1893 block_gas_limit: u64,
1894 tx_gas_limit: u64,
1895 },
1896 TxTypeConflict { transaction: Arc<ValidPoolTransaction<T>> },
1898}
1899
1900#[derive(Debug)]
1902pub(crate) struct InsertOk<T: PoolTransaction> {
1903 transaction: Arc<ValidPoolTransaction<T>>,
1905 move_to: SubPool,
1907 #[allow(dead_code)]
1909 state: TxState,
1910 replaced_tx: Option<(Arc<ValidPoolTransaction<T>>, SubPool)>,
1912 updates: Vec<PoolUpdate>,
1914}
1915
1916#[derive(Debug)]
1919pub(crate) struct PoolInternalTransaction<T: PoolTransaction> {
1920 pub(crate) transaction: Arc<ValidPoolTransaction<T>>,
1922 pub(crate) subpool: SubPool,
1924 pub(crate) state: TxState,
1927 pub(crate) cumulative_cost: U256,
1932}
1933
1934impl<T: PoolTransaction> PoolInternalTransaction<T> {
1937 fn next_cumulative_cost(&self) -> U256 {
1938 self.cumulative_cost + self.transaction.cost()
1939 }
1940}
1941
1942#[derive(Debug)]
1944pub(crate) struct UpdateOutcome<T: PoolTransaction> {
1945 pub(crate) promoted: Vec<Arc<ValidPoolTransaction<T>>>,
1947 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#[derive(Debug, Clone, Default)]
1959pub(crate) struct SenderInfo {
1960 pub(crate) state_nonce: u64,
1962 pub(crate) balance: U256,
1964}
1965
1966impl SenderInfo {
1969 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 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.blob_pool.is_empty());
2074 assert_eq!(pool.pending_pool.len(), 1);
2075
2076 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 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap() + 1);
2083 pool.set_block_info(block_info);
2084
2085 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 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 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.pending_pool.is_empty());
2114 assert_eq!(pool.blob_pool.len(), 1);
2115
2116 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 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap());
2123 pool.set_block_info(block_info);
2124
2125 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 assert_eq!(pool.pending_pool.len(), 1);
2132 assert!(pool.blob_pool.is_empty());
2133 }
2134
2135 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
2137 struct PromotionTest {
2138 basefee: u64,
2140 blobfee: u128,
2142 subpool: SubPool,
2144 basefee_update: u64,
2146 blobfee_update: u128,
2148 new_subpool: SubPool,
2150 }
2151
2152 impl PromotionTest {
2153 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 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 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 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 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 let reversed = expected_promotions.iter().map(|test| test.opposite()).collect::<Vec<_>>();
2296 expected_promotions.extend(reversed);
2297
2298 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 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 promotion_test.assert_single_tx_starting_subpool(&pool);
2317
2318 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 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 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 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 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 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 assert!(!pool.contains(first_added.hash()));
2460 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 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 assert!(pool.contains(first.hash()));
2505 assert_eq!(pool.len(), 1);
2506
2507 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 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 #[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 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 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 assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2584 }
2585
2586 #[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 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 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 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 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 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 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 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 let mut f = MockTransactionFactory::default();
2787 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2788
2789 let tx = MockTransaction::eip1559();
2791 pool.add_transaction(f.validated(tx.clone()), U256::from(1_000), 0).unwrap();
2792
2793 let tx1 = tx.inc_price().next();
2795
2796 let tx1_validated = f.validated(tx1.clone());
2798 pool.add_transaction(tx1_validated, U256::from(1_000), 0).unwrap();
2799
2800 assert_eq!(
2802 pool.get_highest_nonce_by_sender(f.ids.sender_id(&tx.sender()).unwrap()),
2803 Some(1)
2804 );
2805
2806 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 assert_eq!(highest_tx.as_ref().transaction, tx1);
2813 }
2814
2815 #[test]
2816 fn get_highest_consecutive_transaction_by_sender() {
2817 let mut pool = TxPool::new(MockOrdering::default(), PoolConfig::default());
2819 let mut f = MockTransactionFactory::default();
2820
2821 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 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 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 reth_tracing::init_test_tracing();
2886
2887 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 let a_sender = address!("0x000000000000000000000000000000000000000a");
2895
2896 let mut block_info = pool.block_info();
2898 block_info.pending_blob_fee = Some(100);
2899 block_info.pending_basefee = 100;
2900
2901 pool.set_block_info(block_info);
2903
2904 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 for tx in a_txs {
2916 pool.add_transaction(f.validated(tx), U256::from(1_000), 0).unwrap();
2917 }
2918
2919 let removed = pool.discard_worst();
2921 assert_eq!(removed.len(), 1);
2922 }
2923
2924 #[test]
2925 fn discard_with_parked_large_txs() {
2926 reth_tracing::init_test_tracing();
2928
2929 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 let a_sender = address!("0x000000000000000000000000000000000000000a");
2937
2938 let pool_base_fee = 100;
2940 pool.update_basefee(pool_base_fee);
2941
2942 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 for tx in a_txs {
2954 pool.add_transaction(f.validated(tx), U256::from(1_000), 0).unwrap();
2955 }
2956
2957 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 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 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 let v0 = f.validated(tx_0);
3035 let v1 = f.validated(tx_1);
3036 let v2 = f.validated(tx_2);
3037
3038 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 pool.prune_transaction_by_hash(v0.hash());
3047
3048 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce).unwrap();
3050
3051 assert_eq!(1, pool.queued_transactions().len());
3053 assert_eq!(1, pool.pending_transactions().len());
3054
3055 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 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 let v0 = f.validated(tx_0);
3080 let v1 = f.validated(tx_1);
3081
3082 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 pool.remove_transaction(v0.id());
3091 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 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 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 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 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 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 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 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 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 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 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 pool.remove_transaction(v0.id());
3264
3265 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce).unwrap();
3267
3268 assert_eq!(1, pool.queued_transactions().len());
3270 assert_eq!(1, pool.pending_transactions().len());
3271
3272 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 assert_eq!(0, pool.queued_transactions().len());
3284 assert_eq!(2, pool.pending_transactions().len());
3285
3286 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 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 pool.add_transaction(v0.clone(), U256::MAX, 0).unwrap();
3312 assert_eq!(1, pool.queued_transactions().len());
3313
3314 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 #[test]
3328 fn one_sender_one_independent_transaction() {
3329 let mut on_chain_balance = U256::from(4_999); 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 let template =
3337 MockTransaction::eip1559().inc_price().inc_limit().with_value(U256::from(1_001));
3338
3339 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 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 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); assert_eq!(pool.pending_pool.independent().len(), 1);
3368 }
3369}