1use crate::{
4 config::{LocalTransactionConfig, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER},
5 error::{
6 Eip4844PoolTransactionError, Eip7702PoolTransactionError, InvalidPoolTransactionError,
7 PoolError, PoolErrorKind,
8 },
9 identifier::{SenderId, TransactionId},
10 metrics::{AllTransactionsMetrics, TxPoolMetrics},
11 pool::{
12 best::BestTransactions,
13 blob::BlobTransactions,
14 parked::{BasefeeOrd, ParkedPool, QueuedOrd},
15 pending::PendingPool,
16 state::{SubPool, TxState},
17 update::{Destination, PoolUpdate, UpdateOutcome},
18 AddedPendingTransaction, AddedTransaction, OnNewCanonicalStateOutcome,
19 },
20 traits::{BestTransactionsAttributes, BlockInfo, PoolSize},
21 PoolConfig, PoolResult, PoolTransaction, PoolUpdateKind, PriceBumpConfig, TransactionOrdering,
22 ValidPoolTransaction, U256,
23};
24use alloy_consensus::constants::{
25 EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, KECCAK_EMPTY,
26 LEGACY_TX_TYPE_ID,
27};
28use alloy_eips::{
29 eip1559::{ETHEREUM_BLOCK_GAS_LIMIT_30M, MIN_PROTOCOL_BASE_FEE},
30 eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
31 Typed2718,
32};
33use alloy_primitives::{Address, TxHash, B256};
34use rustc_hash::FxHashMap;
35use smallvec::SmallVec;
36use std::{
37 cmp::Ordering,
38 collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet},
39 fmt,
40 ops::Bound::{Excluded, Unbounded},
41 sync::Arc,
42};
43use tracing::trace;
44
45#[cfg_attr(doc, aquamarine::aquamarine)]
46pub struct TxPool<T: TransactionOrdering> {
88 sender_info: FxHashMap<SenderId, SenderInfo>,
90 pending_pool: PendingPool<T>,
94 config: PoolConfig,
96 queued_pool: ParkedPool<QueuedOrd<T::Transaction>>,
103 basefee_pool: ParkedPool<BasefeeOrd<T::Transaction>>,
108 blob_pool: BlobTransactions<T::Transaction>,
115 all_transactions: AllTransactions<T::Transaction>,
117 metrics: TxPoolMetrics,
119 latest_update_kind: Option<PoolUpdateKind>,
121}
122
123impl<T: TransactionOrdering> TxPool<T> {
126 pub fn new(ordering: T, config: PoolConfig) -> Self {
128 Self {
129 sender_info: Default::default(),
130 pending_pool: PendingPool::with_buffer(
131 ordering,
132 config.max_new_pending_txs_notifications,
133 ),
134 queued_pool: Default::default(),
135 basefee_pool: Default::default(),
136 blob_pool: Default::default(),
137 all_transactions: AllTransactions::new(&config),
138 config,
139 metrics: Default::default(),
140 latest_update_kind: None,
141 }
142 }
143
144 pub fn get_highest_nonce_by_sender(&self, sender: SenderId) -> Option<u64> {
146 self.all().txs_iter(sender).last().map(|(_, tx)| tx.transaction.nonce())
147 }
148
149 pub fn get_highest_transaction_by_sender(
152 &self,
153 sender: SenderId,
154 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
155 self.all().txs_iter(sender).last().map(|(_, tx)| Arc::clone(&tx.transaction))
156 }
157
158 pub(crate) fn get_highest_consecutive_transaction_by_sender(
165 &self,
166 mut on_chain: TransactionId,
167 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
168 let mut last_consecutive_tx = None;
169
170 if let Some(current) = self.sender_info.get(&on_chain.sender) {
172 on_chain.nonce = on_chain.nonce.max(current.state_nonce);
173 }
174
175 let mut next_expected_nonce = on_chain.nonce;
176 for (id, tx) in self.all().descendant_txs_inclusive(&on_chain) {
177 if next_expected_nonce != id.nonce {
178 break
179 }
180 next_expected_nonce = id.next_nonce();
181 last_consecutive_tx = Some(tx);
182 }
183
184 last_consecutive_tx.map(|tx| Arc::clone(&tx.transaction))
185 }
186
187 pub(crate) const fn all(&self) -> &AllTransactions<T::Transaction> {
189 &self.all_transactions
190 }
191
192 pub(crate) fn unique_senders(&self) -> HashSet<Address> {
194 self.all_transactions.txs.values().map(|tx| tx.transaction.sender()).collect()
195 }
196
197 pub fn size(&self) -> PoolSize {
199 PoolSize {
200 pending: self.pending_pool.len(),
201 pending_size: self.pending_pool.size(),
202 basefee: self.basefee_pool.len(),
203 basefee_size: self.basefee_pool.size(),
204 queued: self.queued_pool.len(),
205 queued_size: self.queued_pool.size(),
206 blob: self.blob_pool.len(),
207 blob_size: self.blob_pool.size(),
208 total: self.all_transactions.len(),
209 }
210 }
211
212 pub const fn block_info(&self) -> BlockInfo {
214 BlockInfo {
215 block_gas_limit: self.all_transactions.block_gas_limit,
216 last_seen_block_hash: self.all_transactions.last_seen_block_hash,
217 last_seen_block_number: self.all_transactions.last_seen_block_number,
218 pending_basefee: self.all_transactions.pending_fees.base_fee,
219 pending_blob_fee: Some(self.all_transactions.pending_fees.blob_fee),
220 }
221 }
222
223 fn update_blob_fee(&mut self, mut pending_blob_fee: u128, base_fee_update: Ordering) {
225 std::mem::swap(&mut self.all_transactions.pending_fees.blob_fee, &mut pending_blob_fee);
226 match (self.all_transactions.pending_fees.blob_fee.cmp(&pending_blob_fee), base_fee_update)
227 {
228 (Ordering::Equal, Ordering::Equal | Ordering::Greater) => {
229 }
231 (Ordering::Greater, Ordering::Equal | Ordering::Greater) => {
232 let removed =
234 self.pending_pool.update_blob_fee(self.all_transactions.pending_fees.blob_fee);
235 for tx in removed {
236 let to = {
237 let tx =
238 self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
239
240 tx.state.remove(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
242 tx.subpool = tx.state.into();
243 tx.subpool
244 };
245 self.add_transaction_to_subpool(to, tx);
246 }
247 }
248 (Ordering::Less, _) | (_, Ordering::Less) => {
249 let removed =
251 self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees);
252 for tx in removed {
253 let to = {
254 let tx =
255 self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
256 tx.state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
257 tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
258 tx.subpool = tx.state.into();
259 tx.subpool
260 };
261 self.add_transaction_to_subpool(to, tx);
262 }
263 }
264 }
265 }
266
267 fn update_basefee(&mut self, mut pending_basefee: u64) -> Ordering {
272 std::mem::swap(&mut self.all_transactions.pending_fees.base_fee, &mut pending_basefee);
273 match self.all_transactions.pending_fees.base_fee.cmp(&pending_basefee) {
274 Ordering::Equal => {
275 Ordering::Equal
277 }
278 Ordering::Greater => {
279 let removed =
281 self.pending_pool.update_base_fee(self.all_transactions.pending_fees.base_fee);
282 for tx in removed {
283 let to = {
284 let tx =
285 self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
286 tx.state.remove(TxState::ENOUGH_FEE_CAP_BLOCK);
287 tx.subpool = tx.state.into();
288 tx.subpool
289 };
290 self.add_transaction_to_subpool(to, tx);
291 }
292
293 Ordering::Greater
294 }
295 Ordering::Less => {
296 let removed =
298 self.basefee_pool.enforce_basefee(self.all_transactions.pending_fees.base_fee);
299 for tx in removed {
300 let to = {
301 let tx =
302 self.all_transactions.txs.get_mut(tx.id()).expect("tx exists in set");
303 tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
304 tx.subpool = tx.state.into();
305 tx.subpool
306 };
307 self.add_transaction_to_subpool(to, tx);
308 }
309
310 Ordering::Less
311 }
312 }
313 }
314
315 pub fn set_block_info(&mut self, info: BlockInfo) {
319 let BlockInfo {
320 block_gas_limit,
321 last_seen_block_hash,
322 last_seen_block_number,
323 pending_basefee,
324 pending_blob_fee,
325 } = info;
326 self.all_transactions.last_seen_block_hash = last_seen_block_hash;
327 self.all_transactions.last_seen_block_number = last_seen_block_number;
328 let basefee_ordering = self.update_basefee(pending_basefee);
329
330 self.all_transactions.block_gas_limit = block_gas_limit;
331
332 if let Some(blob_fee) = pending_blob_fee {
333 self.update_blob_fee(blob_fee, basefee_ordering)
334 }
335 }
336
337 pub(crate) fn best_transactions(&self) -> BestTransactions<T> {
340 self.pending_pool.best()
341 }
342
343 pub(crate) fn best_transactions_with_attributes(
350 &self,
351 best_transactions_attributes: BestTransactionsAttributes,
352 ) -> Box<dyn crate::traits::BestTransactions<Item = Arc<ValidPoolTransaction<T::Transaction>>>>
353 {
354 match best_transactions_attributes.basefee.cmp(&self.all_transactions.pending_fees.base_fee)
357 {
358 Ordering::Equal => {
359 let new_blob_fee = best_transactions_attributes.blob_fee.unwrap_or_default();
363 match new_blob_fee.cmp(&(self.all_transactions.pending_fees.blob_fee as u64)) {
364 Ordering::Less => {
365 let unlocked =
367 self.blob_pool.satisfy_attributes(best_transactions_attributes);
368 Box::new(self.pending_pool.best_with_unlocked_and_attributes(
369 unlocked,
370 best_transactions_attributes.basefee,
371 new_blob_fee,
372 ))
373 }
374 Ordering::Equal => Box::new(self.pending_pool.best()),
375 Ordering::Greater => {
376 Box::new(self.pending_pool.best_with_basefee_and_blobfee(
378 best_transactions_attributes.basefee,
379 best_transactions_attributes.blob_fee.unwrap_or_default(),
380 ))
381 }
382 }
383 }
384 Ordering::Greater => {
385 let new_blob_fee = best_transactions_attributes.blob_fee.unwrap_or_default();
387 match new_blob_fee.cmp(&(self.all_transactions.pending_fees.blob_fee as u64)) {
388 Ordering::Less => {
389 let unlocked =
391 self.blob_pool.satisfy_attributes(best_transactions_attributes);
392 Box::new(self.pending_pool.best_with_unlocked_and_attributes(
393 unlocked,
394 best_transactions_attributes.basefee,
395 new_blob_fee,
396 ))
397 }
398 Ordering::Equal | Ordering::Greater => {
399 Box::new(self.pending_pool.best_with_basefee_and_blobfee(
401 best_transactions_attributes.basefee,
402 new_blob_fee,
403 ))
404 }
405 }
406 }
407 Ordering::Less => {
408 let mut unlocked = self
411 .basefee_pool
412 .satisfy_base_fee_transactions(best_transactions_attributes.basefee);
413
414 unlocked.extend(self.blob_pool.satisfy_attributes(best_transactions_attributes));
416
417 Box::new(self.pending_pool.best_with_unlocked_and_attributes(
418 unlocked,
419 best_transactions_attributes.basefee,
420 best_transactions_attributes.blob_fee.unwrap_or_default(),
421 ))
422 }
423 }
424 }
425
426 pub(crate) fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
428 self.pending_pool.all().collect()
429 }
430 pub(crate) fn pending_transactions_iter(
432 &self,
433 ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
434 self.pending_pool.all()
435 }
436
437 pub(crate) fn pending_transactions_with_predicate(
439 &self,
440 mut predicate: impl FnMut(&ValidPoolTransaction<T::Transaction>) -> bool,
441 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
442 self.pending_transactions_iter().filter(|tx| predicate(tx)).collect()
443 }
444
445 pub(crate) fn pending_txs_by_sender(
447 &self,
448 sender: SenderId,
449 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
450 self.pending_transactions_iter().filter(|tx| tx.sender_id() == sender).collect()
451 }
452
453 pub(crate) fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
455 self.basefee_pool.all().chain(self.queued_pool.all()).collect()
456 }
457
458 pub(crate) fn queued_transactions_iter(
460 &self,
461 ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
462 self.basefee_pool.all().chain(self.queued_pool.all())
463 }
464
465 pub fn queued_and_pending_txs_by_sender(
467 &self,
468 sender: SenderId,
469 ) -> (SmallVec<[TransactionId; TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER]>, Vec<TransactionId>) {
470 (self.queued_pool.get_txs_by_sender(sender), self.pending_pool.get_txs_by_sender(sender))
471 }
472
473 pub(crate) fn queued_txs_by_sender(
475 &self,
476 sender: SenderId,
477 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
478 self.queued_transactions_iter().filter(|tx| tx.sender_id() == sender).collect()
479 }
480
481 pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
483 self.all_transactions.contains(tx_hash)
484 }
485
486 #[cfg(test)]
488 pub(crate) fn subpool_contains(&self, subpool: SubPool, id: &TransactionId) -> bool {
489 match subpool {
490 SubPool::Queued => self.queued_pool.contains(id),
491 SubPool::Pending => self.pending_pool.contains(id),
492 SubPool::BaseFee => self.basefee_pool.contains(id),
493 SubPool::Blob => self.blob_pool.contains(id),
494 }
495 }
496
497 #[inline]
499 pub(crate) fn is_exceeded(&self) -> bool {
500 self.config.is_exceeded(self.size())
501 }
502
503 pub(crate) fn get(
505 &self,
506 tx_hash: &TxHash,
507 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
508 self.all_transactions.by_hash.get(tx_hash).cloned()
509 }
510
511 pub(crate) fn get_all(
513 &self,
514 txs: Vec<TxHash>,
515 ) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
516 txs.into_iter().filter_map(|tx| self.get(&tx))
517 }
518
519 pub(crate) fn get_transactions_by_sender(
521 &self,
522 sender: SenderId,
523 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
524 self.all_transactions.txs_iter(sender).map(|(_, tx)| Arc::clone(&tx.transaction)).collect()
525 }
526
527 pub(crate) fn update_accounts(
529 &mut self,
530 changed_senders: FxHashMap<SenderId, SenderInfo>,
531 ) -> UpdateOutcome<T::Transaction> {
532 let updates = self.all_transactions.update(&changed_senders);
534
535 self.sender_info.extend(changed_senders);
537
538 let update = self.process_updates(updates);
540 self.update_size_metrics();
542 update
543 }
544
545 pub(crate) fn on_canonical_state_change(
550 &mut self,
551 block_info: BlockInfo,
552 mined_transactions: Vec<TxHash>,
553 changed_senders: FxHashMap<SenderId, SenderInfo>,
554 update_kind: PoolUpdateKind,
555 ) -> OnNewCanonicalStateOutcome<T::Transaction> {
556 let block_hash = block_info.last_seen_block_hash;
558 self.all_transactions.set_block_info(block_info);
559
560 let mut removed_txs_count = 0;
562 for tx_hash in &mined_transactions {
563 if self.prune_transaction_by_hash(tx_hash).is_some() {
564 removed_txs_count += 1;
565 }
566 }
567
568 self.metrics.removed_transactions.increment(removed_txs_count);
570
571 let UpdateOutcome { promoted, discarded } = self.update_accounts(changed_senders);
572
573 self.update_transaction_type_metrics();
574 self.metrics.performed_state_updates.increment(1);
575
576 self.latest_update_kind = Some(update_kind);
578
579 OnNewCanonicalStateOutcome { block_hash, mined: mined_transactions, promoted, discarded }
580 }
581
582 pub(crate) fn update_size_metrics(&self) {
584 let stats = self.size();
585 self.metrics.pending_pool_transactions.set(stats.pending as f64);
586 self.metrics.pending_pool_size_bytes.set(stats.pending_size as f64);
587 self.metrics.basefee_pool_transactions.set(stats.basefee as f64);
588 self.metrics.basefee_pool_size_bytes.set(stats.basefee_size as f64);
589 self.metrics.queued_pool_transactions.set(stats.queued as f64);
590 self.metrics.queued_pool_size_bytes.set(stats.queued_size as f64);
591 self.metrics.blob_pool_transactions.set(stats.blob as f64);
592 self.metrics.blob_pool_size_bytes.set(stats.blob_size as f64);
593 self.metrics.total_transactions.set(stats.total as f64);
594 }
595
596 pub(crate) fn update_transaction_type_metrics(&self) {
598 let mut legacy_count = 0;
599 let mut eip2930_count = 0;
600 let mut eip1559_count = 0;
601 let mut eip4844_count = 0;
602 let mut eip7702_count = 0;
603
604 for tx in self.all_transactions.transactions_iter() {
605 match tx.transaction.ty() {
606 LEGACY_TX_TYPE_ID => legacy_count += 1,
607 EIP2930_TX_TYPE_ID => eip2930_count += 1,
608 EIP1559_TX_TYPE_ID => eip1559_count += 1,
609 EIP4844_TX_TYPE_ID => eip4844_count += 1,
610 EIP7702_TX_TYPE_ID => eip7702_count += 1,
611 _ => {} }
613 }
614
615 self.metrics.total_legacy_transactions.set(legacy_count as f64);
616 self.metrics.total_eip2930_transactions.set(eip2930_count as f64);
617 self.metrics.total_eip1559_transactions.set(eip1559_count as f64);
618 self.metrics.total_eip4844_transactions.set(eip4844_count as f64);
619 self.metrics.total_eip7702_transactions.set(eip7702_count as f64);
620 }
621
622 pub(crate) fn add_transaction(
648 &mut self,
649 tx: ValidPoolTransaction<T::Transaction>,
650 on_chain_balance: U256,
651 on_chain_nonce: u64,
652 on_chain_code_hash: Option<B256>,
653 ) -> PoolResult<AddedTransaction<T::Transaction>> {
654 if self.contains(tx.hash()) {
655 return Err(PoolError::new(*tx.hash(), PoolErrorKind::AlreadyImported))
656 }
657
658 self.validate_auth(&tx, on_chain_nonce, on_chain_code_hash)?;
659
660 self.sender_info
662 .entry(tx.sender_id())
663 .or_default()
664 .update(on_chain_nonce, on_chain_balance);
665
666 match self.all_transactions.insert_tx(tx, on_chain_balance, on_chain_nonce) {
667 Ok(InsertOk { transaction, move_to, replaced_tx, updates, .. }) => {
668 self.add_new_transaction(transaction.clone(), replaced_tx.clone(), move_to);
670 self.metrics.inserted_transactions.increment(1);
672 let UpdateOutcome { promoted, discarded } = self.process_updates(updates);
673
674 let replaced = replaced_tx.map(|(tx, _)| tx);
675
676 let res = if move_to.is_pending() {
678 AddedTransaction::Pending(AddedPendingTransaction {
679 transaction,
680 promoted,
681 discarded,
682 replaced,
683 })
684 } else {
685 AddedTransaction::Parked { transaction, subpool: move_to, replaced }
686 };
687
688 self.update_size_metrics();
690
691 Ok(res)
692 }
693 Err(err) => {
694 self.metrics.invalid_transactions.increment(1);
696 match err {
697 InsertErr::Underpriced { existing: _, transaction } => Err(PoolError::new(
698 *transaction.hash(),
699 PoolErrorKind::ReplacementUnderpriced,
700 )),
701 InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap } => {
702 Err(PoolError::new(
703 *transaction.hash(),
704 PoolErrorKind::FeeCapBelowMinimumProtocolFeeCap(fee_cap),
705 ))
706 }
707 InsertErr::ExceededSenderTransactionsCapacity { transaction } => {
708 Err(PoolError::new(
709 *transaction.hash(),
710 PoolErrorKind::SpammerExceededCapacity(transaction.sender()),
711 ))
712 }
713 InsertErr::TxGasLimitMoreThanAvailableBlockGas {
714 transaction,
715 block_gas_limit,
716 tx_gas_limit,
717 } => Err(PoolError::new(
718 *transaction.hash(),
719 PoolErrorKind::InvalidTransaction(
720 InvalidPoolTransactionError::ExceedsGasLimit(
721 tx_gas_limit,
722 block_gas_limit,
723 ),
724 ),
725 )),
726 InsertErr::BlobTxHasNonceGap { transaction } => Err(PoolError::new(
727 *transaction.hash(),
728 PoolErrorKind::InvalidTransaction(
729 Eip4844PoolTransactionError::Eip4844NonceGap.into(),
730 ),
731 )),
732 InsertErr::Overdraft { transaction } => Err(PoolError::new(
733 *transaction.hash(),
734 PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Overdraft {
735 cost: *transaction.cost(),
736 balance: on_chain_balance,
737 }),
738 )),
739 InsertErr::TxTypeConflict { transaction } => Err(PoolError::new(
740 *transaction.hash(),
741 PoolErrorKind::ExistingConflictingTransactionType(
742 transaction.sender(),
743 transaction.tx_type(),
744 ),
745 )),
746 }
747 }
748 }
749 }
750
751 fn check_delegation_limit(
755 &self,
756 transaction: &ValidPoolTransaction<T::Transaction>,
757 on_chain_nonce: u64,
758 on_chain_code_hash: Option<B256>,
759 ) -> Result<(), PoolError> {
760 if (on_chain_code_hash.is_none() || on_chain_code_hash == Some(KECCAK_EMPTY)) &&
762 !self.all_transactions.auths.contains_key(&transaction.sender_id())
763 {
764 return Ok(())
765 }
766
767 let mut txs_by_sender =
768 self.pending_pool.iter_txs_by_sender(transaction.sender_id()).peekable();
769
770 if txs_by_sender.peek().is_none() {
771 if transaction.nonce() > on_chain_nonce {
773 return Err(PoolError::new(
774 *transaction.hash(),
775 PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Eip7702(
776 Eip7702PoolTransactionError::OutOfOrderTxFromDelegated,
777 )),
778 ))
779 }
780 return Ok(())
781 }
782
783 if txs_by_sender.any(|id| id == &transaction.transaction_id) {
784 return Ok(())
786 }
787
788 Err(PoolError::new(
789 *transaction.hash(),
790 PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Eip7702(
791 Eip7702PoolTransactionError::InflightTxLimitReached,
792 )),
793 ))
794 }
795
796 fn validate_auth(
805 &self,
806 transaction: &ValidPoolTransaction<T::Transaction>,
807 on_chain_nonce: u64,
808 on_chain_code_hash: Option<B256>,
809 ) -> Result<(), PoolError> {
810 self.check_delegation_limit(transaction, on_chain_nonce, on_chain_code_hash)?;
813
814 if let Some(authority_list) = &transaction.authority_ids {
815 for sender_id in authority_list {
816 if self.all_transactions.txs_iter(*sender_id).next().is_some() {
817 return Err(PoolError::new(
818 *transaction.hash(),
819 PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Eip7702(
820 Eip7702PoolTransactionError::AuthorityReserved,
821 )),
822 ))
823 }
824 }
825 }
826
827 Ok(())
828 }
829
830 fn process_updates(&mut self, updates: Vec<PoolUpdate>) -> UpdateOutcome<T::Transaction> {
834 let mut outcome = UpdateOutcome::default();
835 for PoolUpdate { id, hash, current, destination } in updates {
836 match destination {
837 Destination::Discard => {
838 if let Some(tx) = self.prune_transaction_by_hash(&hash) {
840 outcome.discarded.push(tx);
841 }
842 self.metrics.removed_transactions.increment(1);
843 }
844 Destination::Pool(move_to) => {
845 debug_assert_ne!(&move_to, ¤t, "destination must be different");
846 let moved = self.move_transaction(current, move_to, &id);
847 if matches!(move_to, SubPool::Pending) {
848 if let Some(tx) = moved {
849 trace!(target: "txpool", hash=%tx.transaction.hash(), "Promoted transaction to pending");
850 outcome.promoted.push(tx);
851 }
852 }
853 }
854 }
855 }
856 outcome
857 }
858
859 fn move_transaction(
864 &mut self,
865 from: SubPool,
866 to: SubPool,
867 id: &TransactionId,
868 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
869 let tx = self.remove_from_subpool(from, id)?;
870 self.add_transaction_to_subpool(to, tx.clone());
871 Some(tx)
872 }
873
874 pub(crate) fn remove_transactions(
879 &mut self,
880 hashes: Vec<TxHash>,
881 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
882 let txs =
883 hashes.into_iter().filter_map(|hash| self.remove_transaction_by_hash(&hash)).collect();
884 self.update_size_metrics();
885 txs
886 }
887
888 pub(crate) fn remove_transactions_and_descendants(
890 &mut self,
891 hashes: Vec<TxHash>,
892 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
893 let mut removed = Vec::new();
894 for hash in hashes {
895 if let Some(tx) = self.remove_transaction_by_hash(&hash) {
896 removed.push(tx.clone());
897 self.remove_descendants(tx.id(), &mut removed);
898 }
899 }
900 self.update_size_metrics();
901 removed
902 }
903
904 pub(crate) fn remove_transactions_by_sender(
906 &mut self,
907 sender_id: SenderId,
908 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
909 let mut removed = Vec::new();
910 let txs = self.get_transactions_by_sender(sender_id);
911 for tx in txs {
912 if let Some(tx) = self.remove_transaction(tx.id()) {
913 removed.push(tx);
914 }
915 }
916 self.update_size_metrics();
917 removed
918 }
919
920 fn remove_transaction(
924 &mut self,
925 id: &TransactionId,
926 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
927 let (tx, pool) = self.all_transactions.remove_transaction(id)?;
928 self.remove_from_subpool(pool, tx.id())
929 }
930
931 fn remove_transaction_by_hash(
937 &mut self,
938 tx_hash: &B256,
939 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
940 let (tx, pool) = self.all_transactions.remove_transaction_by_hash(tx_hash)?;
941
942 let updates = self.all_transactions.park_descendant_transactions(tx.id());
944 self.process_updates(updates);
945 self.remove_from_subpool(pool, tx.id())
946 }
947
948 fn prune_transaction_by_hash(
955 &mut self,
956 tx_hash: &B256,
957 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
958 let (tx, pool) = self.all_transactions.remove_transaction_by_hash(tx_hash)?;
959 self.remove_from_subpool(pool, tx.id())
960 }
961
962 fn remove_from_subpool(
966 &mut self,
967 pool: SubPool,
968 tx: &TransactionId,
969 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
970 let tx = match pool {
971 SubPool::Queued => self.queued_pool.remove_transaction(tx),
972 SubPool::Pending => self.pending_pool.remove_transaction(tx),
973 SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
974 SubPool::Blob => self.blob_pool.remove_transaction(tx),
975 };
976
977 if let Some(ref tx) = tx {
978 trace!(target: "txpool", hash=%tx.transaction.hash(), ?pool, "Removed transaction from a subpool");
982 }
983
984 tx
985 }
986
987 fn remove_descendants(
991 &mut self,
992 tx: &TransactionId,
993 removed: &mut Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
994 ) {
995 let mut id = *tx;
996
997 loop {
999 let descendant =
1000 self.all_transactions.descendant_txs_exclusive(&id).map(|(id, _)| *id).next();
1001 if let Some(descendant) = descendant {
1002 if let Some(tx) = self.remove_transaction(&descendant) {
1003 removed.push(tx)
1004 }
1005 id = descendant;
1006 } else {
1007 return
1008 }
1009 }
1010 }
1011
1012 fn add_transaction_to_subpool(
1014 &mut self,
1015 pool: SubPool,
1016 tx: Arc<ValidPoolTransaction<T::Transaction>>,
1017 ) {
1018 match pool {
1022 SubPool::Queued => self.queued_pool.add_transaction(tx),
1023 SubPool::Pending => {
1024 self.pending_pool.add_transaction(tx, self.all_transactions.pending_fees.base_fee);
1025 }
1026 SubPool::BaseFee => {
1027 self.basefee_pool.add_transaction(tx);
1028 }
1029 SubPool::Blob => {
1030 self.blob_pool.add_transaction(tx);
1031 }
1032 }
1033 }
1034
1035 fn add_new_transaction(
1038 &mut self,
1039 transaction: Arc<ValidPoolTransaction<T::Transaction>>,
1040 replaced: Option<(Arc<ValidPoolTransaction<T::Transaction>>, SubPool)>,
1041 pool: SubPool,
1042 ) {
1043 if let Some((replaced, replaced_pool)) = replaced {
1044 self.remove_from_subpool(replaced_pool, replaced.id());
1046 }
1047
1048 self.add_transaction_to_subpool(pool, transaction)
1049 }
1050
1051 pub(crate) fn discard_worst(&mut self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1058 let mut removed = Vec::new();
1059
1060 macro_rules! discard_worst {
1062 ($this:ident, $removed:ident, [$($limit:ident => ($pool:ident, $metric:ident)),* $(,)*]) => {
1063 $ (
1064 while $this.$pool.exceeds(&$this.config.$limit)
1065 {
1066 trace!(
1067 target: "txpool",
1068 "discarding transactions from {}, limit: {:?}, curr size: {}, curr len: {}",
1069 stringify!($pool),
1070 $this.config.$limit,
1071 $this.$pool.size(),
1072 $this.$pool.len(),
1073 );
1074
1075 let removed_from_subpool = $this.$pool.truncate_pool($this.config.$limit.clone());
1077
1078 trace!(
1079 target: "txpool",
1080 "removed {} transactions from {}, limit: {:?}, curr size: {}, curr len: {}",
1081 removed_from_subpool.len(),
1082 stringify!($pool),
1083 $this.config.$limit,
1084 $this.$pool.size(),
1085 $this.$pool.len()
1086 );
1087 $this.metrics.$metric.increment(removed_from_subpool.len() as u64);
1088
1089 for tx in removed_from_subpool {
1091 $this.all_transactions.remove_transaction(tx.id());
1092
1093 let id = *tx.id();
1094
1095 removed.push(tx);
1097
1098 $this.remove_descendants(&id, &mut $removed);
1100 }
1101 }
1102
1103 )*
1104 };
1105 }
1106
1107 discard_worst!(
1108 self, removed, [
1109 pending_limit => (pending_pool, pending_transactions_evicted),
1110 basefee_limit => (basefee_pool, basefee_transactions_evicted),
1111 blob_limit => (blob_pool, blob_transactions_evicted),
1112 queued_limit => (queued_pool, queued_transactions_evicted),
1113 ]
1114 );
1115
1116 removed
1117 }
1118
1119 pub(crate) fn len(&self) -> usize {
1121 self.all_transactions.len()
1122 }
1123
1124 pub(crate) fn is_empty(&self) -> bool {
1126 self.all_transactions.is_empty()
1127 }
1128
1129 #[cfg(any(test, feature = "test-utils"))]
1137 pub fn assert_invariants(&self) {
1138 let size = self.size();
1139 let actual = size.basefee + size.pending + size.queued + size.blob;
1140 assert_eq!(
1141 size.total, actual,
1142 "total size must be equal to the sum of all sub-pools, basefee:{}, pending:{}, queued:{}, blob:{}",
1143 size.basefee, size.pending, size.queued, size.blob
1144 );
1145 self.all_transactions.assert_invariants();
1146 self.pending_pool.assert_invariants();
1147 self.basefee_pool.assert_invariants();
1148 self.queued_pool.assert_invariants();
1149 self.blob_pool.assert_invariants();
1150 }
1151}
1152
1153#[cfg(any(test, feature = "test-utils"))]
1154impl TxPool<crate::test_utils::MockOrdering> {
1155 pub fn mock() -> Self {
1157 Self::new(crate::test_utils::MockOrdering::default(), PoolConfig::default())
1158 }
1159}
1160
1161#[cfg(test)]
1162impl<T: TransactionOrdering> Drop for TxPool<T> {
1163 fn drop(&mut self) {
1164 self.assert_invariants();
1165 }
1166}
1167
1168#[cfg(any(test, feature = "test-utils"))]
1170impl<T: TransactionOrdering> TxPool<T> {
1171 pub(crate) const fn pending(&self) -> &PendingPool<T> {
1172 &self.pending_pool
1173 }
1174
1175 pub(crate) const fn base_fee(&self) -> &ParkedPool<BasefeeOrd<T::Transaction>> {
1176 &self.basefee_pool
1177 }
1178
1179 pub(crate) const fn queued(&self) -> &ParkedPool<QueuedOrd<T::Transaction>> {
1180 &self.queued_pool
1181 }
1182}
1183
1184impl<T: TransactionOrdering> fmt::Debug for TxPool<T> {
1185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1186 f.debug_struct("TxPool").field("config", &self.config).finish_non_exhaustive()
1187 }
1188}
1189
1190pub(crate) struct AllTransactions<T: PoolTransaction> {
1195 minimal_protocol_basefee: u64,
1199 block_gas_limit: u64,
1201 max_account_slots: usize,
1203 by_hash: HashMap<TxHash, Arc<ValidPoolTransaction<T>>>,
1205 txs: BTreeMap<TransactionId, PoolInternalTransaction<T>>,
1207 tx_counter: FxHashMap<SenderId, usize>,
1209 last_seen_block_number: u64,
1211 last_seen_block_hash: B256,
1213 pending_fees: PendingFees,
1215 price_bumps: PriceBumpConfig,
1217 local_transactions_config: LocalTransactionConfig,
1219 auths: FxHashMap<SenderId, HashSet<TxHash>>,
1221 metrics: AllTransactionsMetrics,
1223}
1224
1225impl<T: PoolTransaction> AllTransactions<T> {
1226 fn new(config: &PoolConfig) -> Self {
1228 Self {
1229 max_account_slots: config.max_account_slots,
1230 price_bumps: config.price_bumps,
1231 local_transactions_config: config.local_transactions_config.clone(),
1232 minimal_protocol_basefee: config.minimal_protocol_basefee,
1233 block_gas_limit: config.gas_limit,
1234 ..Default::default()
1235 }
1236 }
1237
1238 #[expect(dead_code)]
1240 pub(crate) fn hashes_iter(&self) -> impl Iterator<Item = TxHash> + '_ {
1241 self.by_hash.keys().copied()
1242 }
1243
1244 pub(crate) fn transactions_iter(
1246 &self,
1247 ) -> impl Iterator<Item = &Arc<ValidPoolTransaction<T>>> + '_ {
1248 self.by_hash.values()
1249 }
1250
1251 pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
1253 self.by_hash.contains_key(tx_hash)
1254 }
1255
1256 pub(crate) fn get(&self, id: &TransactionId) -> Option<&PoolInternalTransaction<T>> {
1258 self.txs.get(id)
1259 }
1260
1261 pub(crate) fn tx_inc(&mut self, sender: SenderId) {
1263 let count = self.tx_counter.entry(sender).or_default();
1264 *count += 1;
1265 self.metrics.all_transactions_by_all_senders.increment(1.0);
1266 }
1267
1268 pub(crate) fn tx_decr(&mut self, sender: SenderId) {
1270 if let hash_map::Entry::Occupied(mut entry) = self.tx_counter.entry(sender) {
1271 let count = entry.get_mut();
1272 if *count == 1 {
1273 entry.remove();
1274 self.metrics.all_transactions_by_all_senders.decrement(1.0);
1275 return
1276 }
1277 *count -= 1;
1278 self.metrics.all_transactions_by_all_senders.decrement(1.0);
1279 }
1280 }
1281
1282 fn set_block_info(&mut self, block_info: BlockInfo) {
1284 let BlockInfo {
1285 block_gas_limit,
1286 last_seen_block_hash,
1287 last_seen_block_number,
1288 pending_basefee,
1289 pending_blob_fee,
1290 } = block_info;
1291 self.last_seen_block_number = last_seen_block_number;
1292 self.last_seen_block_hash = last_seen_block_hash;
1293
1294 self.pending_fees.base_fee = pending_basefee;
1295 self.metrics.base_fee.set(pending_basefee as f64);
1296
1297 self.block_gas_limit = block_gas_limit;
1298
1299 if let Some(pending_blob_fee) = pending_blob_fee {
1300 self.pending_fees.blob_fee = pending_blob_fee;
1301 self.metrics.blob_base_fee.set(pending_blob_fee as f64);
1302 }
1303 }
1304
1305 pub(crate) fn update_size_metrics(&self) {
1307 self.metrics.all_transactions_by_hash.set(self.by_hash.len() as f64);
1308 self.metrics.all_transactions_by_id.set(self.txs.len() as f64);
1309 }
1310
1311 pub(crate) fn update(
1328 &mut self,
1329 changed_accounts: &FxHashMap<SenderId, SenderInfo>,
1330 ) -> Vec<PoolUpdate> {
1331 let mut updates = Vec::with_capacity(64);
1333
1334 let mut iter = self.txs.iter_mut().peekable();
1335
1336 'transactions: while let Some((id, tx)) = iter.next() {
1346 macro_rules! next_sender {
1347 ($iter:ident) => {
1348 'this: while let Some((peek, _)) = iter.peek() {
1349 if peek.sender != id.sender {
1350 break 'this
1351 }
1352 iter.next();
1353 }
1354 };
1355 }
1356 let mut changed_balance = None;
1358
1359 if let Some(info) = changed_accounts.get(&id.sender) {
1361 if id.nonce < info.state_nonce {
1363 updates.push(PoolUpdate {
1364 id: *tx.transaction.id(),
1365 hash: *tx.transaction.hash(),
1366 current: tx.subpool,
1367 destination: Destination::Discard,
1368 });
1369 continue 'transactions
1370 }
1371
1372 let ancestor = TransactionId::ancestor(id.nonce, info.state_nonce, id.sender);
1373 if ancestor.is_none() {
1375 tx.state.insert(TxState::NO_NONCE_GAPS);
1376 tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1377 tx.cumulative_cost = U256::ZERO;
1378 if tx.transaction.cost() > &info.balance {
1379 tx.state.remove(TxState::ENOUGH_BALANCE);
1381 } else {
1382 tx.state.insert(TxState::ENOUGH_BALANCE);
1383 }
1384 }
1385
1386 changed_balance = Some(&info.balance);
1387 }
1388
1389 if tx.state.has_nonce_gap() {
1391 next_sender!(iter);
1392 continue 'transactions
1393 }
1394
1395 tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1397
1398 Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1400 Self::record_subpool_update(&mut updates, tx);
1402
1403 let mut has_parked_ancestor = !tx.state.is_pending();
1405
1406 let mut cumulative_cost = tx.next_cumulative_cost();
1407
1408 let mut next_nonce_in_line = tx.transaction.nonce().saturating_add(1);
1410
1411 while let Some((peek, tx)) = iter.peek_mut() {
1413 if peek.sender != id.sender {
1414 continue 'transactions
1416 }
1417
1418 if tx.transaction.nonce() == next_nonce_in_line {
1419 tx.state.insert(TxState::NO_NONCE_GAPS);
1421 } else {
1422 next_sender!(iter);
1424 continue 'transactions
1425 }
1426
1427 next_nonce_in_line = next_nonce_in_line.saturating_add(1);
1429
1430 tx.cumulative_cost = cumulative_cost;
1432 cumulative_cost = tx.next_cumulative_cost();
1434
1435 if let Some(changed_balance) = changed_balance {
1437 if &cumulative_cost > changed_balance {
1438 tx.state.remove(TxState::ENOUGH_BALANCE);
1440 } else {
1441 tx.state.insert(TxState::ENOUGH_BALANCE);
1442 }
1443 }
1444
1445 if has_parked_ancestor {
1447 tx.state.remove(TxState::NO_PARKED_ANCESTORS);
1448 } else {
1449 tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1450 }
1451 has_parked_ancestor = !tx.state.is_pending();
1452
1453 Self::update_tx_base_fee(self.pending_fees.base_fee, tx);
1455 Self::record_subpool_update(&mut updates, tx);
1456
1457 iter.next();
1459 }
1460 }
1461
1462 updates
1463 }
1464
1465 fn record_subpool_update(updates: &mut Vec<PoolUpdate>, tx: &mut PoolInternalTransaction<T>) {
1470 let current_pool = tx.subpool;
1471 tx.subpool = tx.state.into();
1472 if current_pool != tx.subpool {
1473 updates.push(PoolUpdate {
1474 id: *tx.transaction.id(),
1475 hash: *tx.transaction.hash(),
1476 current: current_pool,
1477 destination: tx.subpool.into(),
1478 })
1479 }
1480 }
1481
1482 fn update_tx_base_fee(pending_block_base_fee: u64, tx: &mut PoolInternalTransaction<T>) {
1484 match tx.transaction.max_fee_per_gas().cmp(&(pending_block_base_fee as u128)) {
1486 Ordering::Greater | Ordering::Equal => {
1487 tx.state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
1488 }
1489 Ordering::Less => {
1490 tx.state.remove(TxState::ENOUGH_FEE_CAP_BLOCK);
1491 }
1492 }
1493 }
1494
1495 pub(crate) fn txs_iter(
1498 &self,
1499 sender: SenderId,
1500 ) -> impl Iterator<Item = (&TransactionId, &PoolInternalTransaction<T>)> + '_ {
1501 self.txs
1502 .range((sender.start_bound(), Unbounded))
1503 .take_while(move |(other, _)| sender == other.sender)
1504 }
1505
1506 #[cfg(test)]
1509 #[expect(dead_code)]
1510 pub(crate) fn txs_iter_mut(
1511 &mut self,
1512 sender: SenderId,
1513 ) -> impl Iterator<Item = (&TransactionId, &mut PoolInternalTransaction<T>)> + '_ {
1514 self.txs
1515 .range_mut((sender.start_bound(), Unbounded))
1516 .take_while(move |(other, _)| sender == other.sender)
1517 }
1518
1519 pub(crate) fn descendant_txs_exclusive<'a, 'b: 'a>(
1523 &'a self,
1524 id: &'b TransactionId,
1525 ) -> impl Iterator<Item = (&'a TransactionId, &'a PoolInternalTransaction<T>)> + 'a {
1526 self.txs.range((Excluded(id), Unbounded)).take_while(|(other, _)| id.sender == other.sender)
1527 }
1528
1529 pub(crate) fn descendant_txs_inclusive<'a, 'b: 'a>(
1534 &'a self,
1535 id: &'b TransactionId,
1536 ) -> impl Iterator<Item = (&'a TransactionId, &'a PoolInternalTransaction<T>)> + 'a {
1537 self.txs.range(id..).take_while(|(other, _)| id.sender == other.sender)
1538 }
1539
1540 pub(crate) fn descendant_txs_mut<'a, 'b: 'a>(
1545 &'a mut self,
1546 id: &'b TransactionId,
1547 ) -> impl Iterator<Item = (&'a TransactionId, &'a mut PoolInternalTransaction<T>)> + 'a {
1548 self.txs.range_mut(id..).take_while(|(other, _)| id.sender == other.sender)
1549 }
1550
1551 pub(crate) fn remove_transaction_by_hash(
1553 &mut self,
1554 tx_hash: &B256,
1555 ) -> Option<(Arc<ValidPoolTransaction<T>>, SubPool)> {
1556 let tx = self.by_hash.remove(tx_hash)?;
1557 let internal = self.txs.remove(&tx.transaction_id)?;
1558 self.remove_auths(&internal);
1559 self.tx_decr(tx.sender_id());
1561 self.update_size_metrics();
1562 Some((tx, internal.subpool))
1563 }
1564
1565 pub(crate) fn park_descendant_transactions(
1567 &mut self,
1568 tx_id: &TransactionId,
1569 ) -> Vec<PoolUpdate> {
1570 let mut updates = Vec::new();
1571
1572 for (id, tx) in self.descendant_txs_mut(tx_id) {
1573 let current_pool = tx.subpool;
1574
1575 tx.state.remove(TxState::NO_NONCE_GAPS);
1576
1577 tx.subpool = tx.state.into();
1579
1580 if current_pool != tx.subpool {
1582 updates.push(PoolUpdate {
1583 id: *id,
1584 hash: *tx.transaction.hash(),
1585 current: current_pool,
1586 destination: tx.subpool.into(),
1587 })
1588 }
1589 }
1590
1591 updates
1592 }
1593
1594 pub(crate) fn remove_transaction(
1600 &mut self,
1601 id: &TransactionId,
1602 ) -> Option<(Arc<ValidPoolTransaction<T>>, SubPool)> {
1603 let internal = self.txs.remove(id)?;
1604
1605 self.tx_decr(internal.transaction.sender_id());
1607
1608 let result =
1609 self.by_hash.remove(internal.transaction.hash()).map(|tx| (tx, internal.subpool));
1610
1611 self.remove_auths(&internal);
1612
1613 self.update_size_metrics();
1614
1615 result
1616 }
1617
1618 fn remove_auths(&mut self, tx: &PoolInternalTransaction<T>) {
1622 let Some(auths) = &tx.transaction.authority_ids else { return };
1623
1624 let tx_hash = tx.transaction.hash();
1625 for auth in auths {
1626 if let Some(list) = self.auths.get_mut(auth) {
1627 list.remove(tx_hash);
1628 if list.is_empty() {
1629 self.auths.remove(auth);
1630 }
1631 }
1632 }
1633 }
1634
1635 #[inline]
1641 fn contains_conflicting_transaction(&self, tx: &ValidPoolTransaction<T>) -> bool {
1642 self.txs_iter(tx.transaction_id.sender)
1643 .next()
1644 .is_some_and(|(_, existing)| tx.tx_type_conflicts_with(&existing.transaction))
1645 }
1646
1647 fn ensure_valid(
1656 &self,
1657 transaction: ValidPoolTransaction<T>,
1658 on_chain_nonce: u64,
1659 ) -> Result<ValidPoolTransaction<T>, InsertErr<T>> {
1660 if !self.local_transactions_config.is_local(transaction.origin, transaction.sender_ref()) {
1661 let current_txs =
1662 self.tx_counter.get(&transaction.sender_id()).copied().unwrap_or_default();
1663
1664 if current_txs >= self.max_account_slots && transaction.nonce() > on_chain_nonce {
1667 return Err(InsertErr::ExceededSenderTransactionsCapacity {
1668 transaction: Arc::new(transaction),
1669 })
1670 }
1671 }
1672 if transaction.gas_limit() > self.block_gas_limit {
1673 return Err(InsertErr::TxGasLimitMoreThanAvailableBlockGas {
1674 block_gas_limit: self.block_gas_limit,
1675 tx_gas_limit: transaction.gas_limit(),
1676 transaction: Arc::new(transaction),
1677 })
1678 }
1679
1680 if self.contains_conflicting_transaction(&transaction) {
1681 return Err(InsertErr::TxTypeConflict { transaction: Arc::new(transaction) })
1683 }
1684
1685 Ok(transaction)
1686 }
1687
1688 fn ensure_valid_blob_transaction(
1694 &self,
1695 new_blob_tx: ValidPoolTransaction<T>,
1696 on_chain_balance: U256,
1697 ancestor: Option<TransactionId>,
1698 ) -> Result<ValidPoolTransaction<T>, InsertErr<T>> {
1699 if let Some(ancestor) = ancestor {
1700 let Some(ancestor_tx) = self.txs.get(&ancestor) else {
1701 self.metrics.blob_transactions_nonce_gaps.increment(1);
1703 return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
1704 };
1705 if ancestor_tx.state.has_nonce_gap() {
1706 self.metrics.blob_transactions_nonce_gaps.increment(1);
1709 return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
1710 }
1711
1712 let mut cumulative_cost = ancestor_tx.next_cumulative_cost() + new_blob_tx.cost();
1714
1715 if cumulative_cost > on_chain_balance {
1717 return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1719 }
1720
1721 let id = new_blob_tx.transaction_id;
1724 let mut descendants = self.descendant_txs_inclusive(&id).peekable();
1725 if let Some((maybe_replacement, _)) = descendants.peek() {
1726 if **maybe_replacement == new_blob_tx.transaction_id {
1727 descendants.next();
1729
1730 for (_, tx) in descendants {
1732 cumulative_cost += tx.transaction.cost();
1733 if tx.transaction.is_eip4844() && cumulative_cost > on_chain_balance {
1734 return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1736 }
1737 }
1738 }
1739 }
1740 } else if new_blob_tx.cost() > &on_chain_balance {
1741 return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
1743 }
1744
1745 Ok(new_blob_tx)
1746 }
1747
1748 pub(crate) fn insert_tx(
1780 &mut self,
1781 transaction: ValidPoolTransaction<T>,
1782 on_chain_balance: U256,
1783 on_chain_nonce: u64,
1784 ) -> InsertResult<T> {
1785 assert!(on_chain_nonce <= transaction.nonce(), "Invalid transaction");
1786
1787 let mut transaction = self.ensure_valid(transaction, on_chain_nonce)?;
1788
1789 let inserted_tx_id = *transaction.id();
1790 let mut state = TxState::default();
1791 let mut cumulative_cost = U256::ZERO;
1792 let mut updates = Vec::new();
1793
1794 state.insert(TxState::NOT_TOO_MUCH_GAS);
1796
1797 let ancestor = TransactionId::ancestor(
1800 transaction.transaction.nonce(),
1801 on_chain_nonce,
1802 inserted_tx_id.sender,
1803 );
1804
1805 if transaction.is_eip4844() {
1808 state.insert(TxState::BLOB_TRANSACTION);
1809
1810 transaction =
1811 self.ensure_valid_blob_transaction(transaction, on_chain_balance, ancestor)?;
1812 let blob_fee_cap = transaction.transaction.max_fee_per_blob_gas().unwrap_or_default();
1813 if blob_fee_cap >= self.pending_fees.blob_fee {
1814 state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
1815 }
1816 } else {
1817 state.insert(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK);
1819 }
1820
1821 let transaction = Arc::new(transaction);
1822
1823 if ancestor.is_none() {
1825 state.insert(TxState::NO_NONCE_GAPS);
1826 state.insert(TxState::NO_PARKED_ANCESTORS);
1827 }
1828
1829 let fee_cap = transaction.max_fee_per_gas();
1831
1832 if fee_cap < self.minimal_protocol_basefee as u128 {
1833 return Err(InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap })
1834 }
1835 if fee_cap >= self.pending_fees.base_fee as u128 {
1836 state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
1837 }
1838
1839 let mut replaced_tx = None;
1841
1842 let pool_tx = PoolInternalTransaction {
1843 transaction: Arc::clone(&transaction),
1844 subpool: state.into(),
1845 state,
1846 cumulative_cost,
1847 };
1848
1849 match self.txs.entry(*transaction.id()) {
1851 Entry::Vacant(entry) => {
1852 self.by_hash.insert(*pool_tx.transaction.hash(), pool_tx.transaction.clone());
1854 entry.insert(pool_tx);
1855 }
1856 Entry::Occupied(mut entry) => {
1857 let existing_transaction = entry.get().transaction.as_ref();
1859 let maybe_replacement = transaction.as_ref();
1860
1861 if existing_transaction.is_underpriced(maybe_replacement, &self.price_bumps) {
1863 return Err(InsertErr::Underpriced {
1864 transaction: pool_tx.transaction,
1865 existing: *entry.get().transaction.hash(),
1866 })
1867 }
1868 let new_hash = *pool_tx.transaction.hash();
1869 let new_transaction = pool_tx.transaction.clone();
1870 let replaced = entry.insert(pool_tx);
1871 self.by_hash.remove(replaced.transaction.hash());
1872 self.by_hash.insert(new_hash, new_transaction);
1873
1874 self.remove_auths(&replaced);
1875
1876 replaced_tx = Some((replaced.transaction, replaced.subpool));
1878 }
1879 }
1880
1881 if let Some(auths) = &transaction.authority_ids {
1882 let tx_hash = transaction.hash();
1883 for auth in auths {
1884 self.auths.entry(*auth).or_default().insert(*tx_hash);
1885 }
1886 }
1887
1888 let on_chain_id = TransactionId::new(transaction.sender_id(), on_chain_nonce);
1890 {
1891 let mut next_nonce = on_chain_id.nonce;
1893
1894 let mut has_parked_ancestor = false;
1898
1899 for (id, tx) in self.descendant_txs_mut(&on_chain_id) {
1902 let current_pool = tx.subpool;
1903
1904 if next_nonce != id.nonce {
1906 break
1907 }
1908
1909 tx.state.insert(TxState::NO_NONCE_GAPS);
1911
1912 tx.cumulative_cost = cumulative_cost;
1914
1915 cumulative_cost = tx.next_cumulative_cost();
1917
1918 if cumulative_cost > on_chain_balance {
1919 tx.state.remove(TxState::ENOUGH_BALANCE);
1921 } else {
1922 tx.state.insert(TxState::ENOUGH_BALANCE);
1923 }
1924
1925 if has_parked_ancestor {
1927 tx.state.remove(TxState::NO_PARKED_ANCESTORS);
1928 } else {
1929 tx.state.insert(TxState::NO_PARKED_ANCESTORS);
1930 }
1931 has_parked_ancestor = !tx.state.is_pending();
1932
1933 tx.subpool = tx.state.into();
1935
1936 if inserted_tx_id.eq(id) {
1937 state = tx.state;
1939 } else {
1940 if current_pool != tx.subpool {
1942 updates.push(PoolUpdate {
1943 id: *id,
1944 hash: *tx.transaction.hash(),
1945 current: current_pool,
1946 destination: tx.subpool.into(),
1947 })
1948 }
1949 }
1950
1951 next_nonce = id.next_nonce();
1953 }
1954 }
1955
1956 if replaced_tx.is_none() {
1958 self.tx_inc(inserted_tx_id.sender);
1959 }
1960
1961 self.update_size_metrics();
1962
1963 let res = Ok(InsertOk { transaction, move_to: state.into(), state, replaced_tx, updates });
1964 res
1965 }
1966
1967 pub(crate) fn len(&self) -> usize {
1969 self.txs.len()
1970 }
1971
1972 pub(crate) fn is_empty(&self) -> bool {
1974 self.txs.is_empty()
1975 }
1976
1977 #[cfg(any(test, feature = "test-utils"))]
1979 pub(crate) fn assert_invariants(&self) {
1980 assert_eq!(self.by_hash.len(), self.txs.len(), "by_hash.len() != txs.len()");
1981 assert!(self.auths.len() <= self.txs.len(), "auths > txs.len()");
1982 }
1983}
1984
1985#[cfg(test)]
1986impl<T: PoolTransaction> AllTransactions<T> {
1987 pub(crate) fn tx_count(&self, sender: SenderId) -> usize {
1991 self.tx_counter.get(&sender).copied().unwrap_or_default()
1992 }
1993}
1994
1995impl<T: PoolTransaction> Default for AllTransactions<T> {
1996 fn default() -> Self {
1997 Self {
1998 max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
1999 minimal_protocol_basefee: MIN_PROTOCOL_BASE_FEE,
2000 block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
2001 by_hash: Default::default(),
2002 txs: Default::default(),
2003 tx_counter: Default::default(),
2004 last_seen_block_number: Default::default(),
2005 last_seen_block_hash: Default::default(),
2006 pending_fees: Default::default(),
2007 price_bumps: Default::default(),
2008 local_transactions_config: Default::default(),
2009 auths: Default::default(),
2010 metrics: Default::default(),
2011 }
2012 }
2013}
2014
2015#[derive(Debug, Clone)]
2017pub(crate) struct PendingFees {
2018 pub(crate) base_fee: u64,
2020 pub(crate) blob_fee: u128,
2022}
2023
2024impl Default for PendingFees {
2025 fn default() -> Self {
2026 Self { base_fee: Default::default(), blob_fee: BLOB_TX_MIN_BLOB_GASPRICE }
2027 }
2028}
2029
2030pub(crate) type InsertResult<T> = Result<InsertOk<T>, InsertErr<T>>;
2032
2033#[derive(Debug)]
2035pub(crate) enum InsertErr<T: PoolTransaction> {
2036 Underpriced {
2038 transaction: Arc<ValidPoolTransaction<T>>,
2039 #[expect(dead_code)]
2040 existing: TxHash,
2041 },
2042 BlobTxHasNonceGap { transaction: Arc<ValidPoolTransaction<T>> },
2044 Overdraft { transaction: Arc<ValidPoolTransaction<T>> },
2047 FeeCapBelowMinimumProtocolFeeCap { transaction: Arc<ValidPoolTransaction<T>>, fee_cap: u128 },
2051 ExceededSenderTransactionsCapacity { transaction: Arc<ValidPoolTransaction<T>> },
2055 TxGasLimitMoreThanAvailableBlockGas {
2057 transaction: Arc<ValidPoolTransaction<T>>,
2058 block_gas_limit: u64,
2059 tx_gas_limit: u64,
2060 },
2061 TxTypeConflict { transaction: Arc<ValidPoolTransaction<T>> },
2063}
2064
2065#[derive(Debug)]
2067pub(crate) struct InsertOk<T: PoolTransaction> {
2068 transaction: Arc<ValidPoolTransaction<T>>,
2070 move_to: SubPool,
2072 #[cfg_attr(not(test), expect(dead_code))]
2074 state: TxState,
2075 replaced_tx: Option<(Arc<ValidPoolTransaction<T>>, SubPool)>,
2077 updates: Vec<PoolUpdate>,
2079}
2080
2081#[derive(Debug)]
2084pub(crate) struct PoolInternalTransaction<T: PoolTransaction> {
2085 pub(crate) transaction: Arc<ValidPoolTransaction<T>>,
2087 pub(crate) subpool: SubPool,
2089 pub(crate) state: TxState,
2092 pub(crate) cumulative_cost: U256,
2097}
2098
2099impl<T: PoolTransaction> PoolInternalTransaction<T> {
2102 fn next_cumulative_cost(&self) -> U256 {
2103 self.cumulative_cost + self.transaction.cost()
2104 }
2105}
2106
2107#[derive(Debug, Clone, Default)]
2109pub(crate) struct SenderInfo {
2110 pub(crate) state_nonce: u64,
2112 pub(crate) balance: U256,
2114}
2115
2116impl SenderInfo {
2119 const fn update(&mut self, state_nonce: u64, balance: U256) {
2121 *self = Self { state_nonce, balance };
2122 }
2123}
2124
2125#[cfg(test)]
2126mod tests {
2127 use super::*;
2128 use crate::{
2129 test_utils::{MockOrdering, MockTransaction, MockTransactionFactory, MockTransactionSet},
2130 traits::TransactionOrigin,
2131 SubPoolLimit,
2132 };
2133 use alloy_consensus::{Transaction, TxType};
2134 use alloy_primitives::address;
2135
2136 #[test]
2137 fn test_insert_blob() {
2138 let on_chain_balance = U256::MAX;
2139 let on_chain_nonce = 0;
2140 let mut f = MockTransactionFactory::default();
2141 let mut pool = AllTransactions::default();
2142 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2143 let valid_tx = f.validated(tx);
2144 let InsertOk { updates, replaced_tx, move_to, state, .. } =
2145 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2146 assert!(updates.is_empty());
2147 assert!(replaced_tx.is_none());
2148 assert!(state.contains(TxState::NO_NONCE_GAPS));
2149 assert!(state.contains(TxState::ENOUGH_BALANCE));
2150 assert!(state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2151 assert_eq!(move_to, SubPool::Pending);
2152
2153 let inserted = pool.txs.get(&valid_tx.transaction_id).unwrap();
2154 assert_eq!(inserted.subpool, SubPool::Pending);
2155 }
2156
2157 #[test]
2158 fn test_insert_blob_not_enough_blob_fee() {
2159 let on_chain_balance = U256::MAX;
2160 let on_chain_nonce = 0;
2161 let mut f = MockTransactionFactory::default();
2162 let mut pool = AllTransactions {
2163 pending_fees: PendingFees { blob_fee: 10_000_000, ..Default::default() },
2164 ..Default::default()
2165 };
2166 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2167 pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap() + 1;
2168 let valid_tx = f.validated(tx);
2169 let InsertOk { state, .. } =
2170 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2171 assert!(state.contains(TxState::NO_NONCE_GAPS));
2172 assert!(!state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2173
2174 let _ = pool.txs.get(&valid_tx.transaction_id).unwrap();
2175 }
2176
2177 #[test]
2178 fn test_valid_tx_with_decreasing_blob_fee() {
2179 let on_chain_balance = U256::MAX;
2180 let on_chain_nonce = 0;
2181 let mut f = MockTransactionFactory::default();
2182 let mut pool = AllTransactions {
2183 pending_fees: PendingFees { blob_fee: 10_000_000, ..Default::default() },
2184 ..Default::default()
2185 };
2186 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2187
2188 pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap() + 1;
2189 let valid_tx = f.validated(tx.clone());
2190 let InsertOk { state, .. } =
2191 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2192 assert!(state.contains(TxState::NO_NONCE_GAPS));
2193 assert!(!state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2194
2195 let _ = pool.txs.get(&valid_tx.transaction_id).unwrap();
2196 pool.remove_transaction(&valid_tx.transaction_id);
2197
2198 pool.pending_fees.blob_fee = tx.max_fee_per_blob_gas().unwrap();
2199 let InsertOk { state, .. } =
2200 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2201 assert!(state.contains(TxState::NO_NONCE_GAPS));
2202 assert!(state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2203 }
2204
2205 #[test]
2206 fn test_demote_valid_tx_with_increasing_blob_fee() {
2207 let on_chain_balance = U256::MAX;
2208 let on_chain_nonce = 0;
2209 let mut f = MockTransactionFactory::default();
2210 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2211 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2212
2213 let mut block_info = pool.block_info();
2215 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap());
2216 pool.set_block_info(block_info);
2217
2218 let validated = f.validated(tx.clone());
2219 let id = *validated.id();
2220 pool.add_transaction(validated, on_chain_balance, on_chain_nonce, None).unwrap();
2221
2222 assert!(pool.blob_pool.is_empty());
2224 assert_eq!(pool.pending_pool.len(), 1);
2225
2226 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2228 assert!(internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2229 assert_eq!(internal_tx.subpool, SubPool::Pending);
2230
2231 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap() + 1);
2233 pool.set_block_info(block_info);
2234
2235 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2237 assert!(!internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2238 assert_eq!(internal_tx.subpool, SubPool::Blob);
2239
2240 assert_eq!(pool.blob_pool.len(), 1);
2242 assert!(pool.pending_pool.is_empty());
2243 }
2244
2245 #[test]
2246 fn test_promote_valid_tx_with_decreasing_blob_fee() {
2247 let on_chain_balance = U256::MAX;
2248 let on_chain_nonce = 0;
2249 let mut f = MockTransactionFactory::default();
2250 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2251 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2252
2253 let mut block_info = pool.block_info();
2255 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap() + 1);
2256 pool.set_block_info(block_info);
2257
2258 let validated = f.validated(tx.clone());
2259 let id = *validated.id();
2260 pool.add_transaction(validated, on_chain_balance, on_chain_nonce, None).unwrap();
2261
2262 assert!(pool.pending_pool.is_empty());
2264 assert_eq!(pool.blob_pool.len(), 1);
2265
2266 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2268 assert!(!internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2269 assert_eq!(internal_tx.subpool, SubPool::Blob);
2270
2271 block_info.pending_blob_fee = Some(tx.max_fee_per_blob_gas().unwrap());
2273 pool.set_block_info(block_info);
2274
2275 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2277 assert!(internal_tx.state.contains(TxState::ENOUGH_BLOB_FEE_CAP_BLOCK));
2278 assert_eq!(internal_tx.subpool, SubPool::Pending);
2279
2280 assert_eq!(pool.pending_pool.len(), 1);
2282 assert!(pool.blob_pool.is_empty());
2283 }
2284
2285 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
2287 struct PromotionTest {
2288 basefee: u64,
2290 blobfee: u128,
2292 subpool: SubPool,
2294 basefee_update: u64,
2296 blobfee_update: u128,
2298 new_subpool: SubPool,
2300 }
2301
2302 impl PromotionTest {
2303 const fn opposite(&self) -> Self {
2305 Self {
2306 basefee: self.basefee_update,
2307 blobfee: self.blobfee_update,
2308 subpool: self.new_subpool,
2309 blobfee_update: self.blobfee,
2310 basefee_update: self.basefee,
2311 new_subpool: self.subpool,
2312 }
2313 }
2314
2315 fn assert_subpool_lengths<T: TransactionOrdering>(
2316 &self,
2317 pool: &TxPool<T>,
2318 failure_message: String,
2319 check_subpool: SubPool,
2320 ) {
2321 match check_subpool {
2322 SubPool::Blob => {
2323 assert_eq!(pool.blob_pool.len(), 1, "{failure_message}");
2324 assert!(pool.pending_pool.is_empty(), "{failure_message}");
2325 assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2326 assert!(pool.queued_pool.is_empty(), "{failure_message}");
2327 }
2328 SubPool::Pending => {
2329 assert!(pool.blob_pool.is_empty(), "{failure_message}");
2330 assert_eq!(pool.pending_pool.len(), 1, "{failure_message}");
2331 assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2332 assert!(pool.queued_pool.is_empty(), "{failure_message}");
2333 }
2334 SubPool::BaseFee => {
2335 assert!(pool.blob_pool.is_empty(), "{failure_message}");
2336 assert!(pool.pending_pool.is_empty(), "{failure_message}");
2337 assert_eq!(pool.basefee_pool.len(), 1, "{failure_message}");
2338 assert!(pool.queued_pool.is_empty(), "{failure_message}");
2339 }
2340 SubPool::Queued => {
2341 assert!(pool.blob_pool.is_empty(), "{failure_message}");
2342 assert!(pool.pending_pool.is_empty(), "{failure_message}");
2343 assert!(pool.basefee_pool.is_empty(), "{failure_message}");
2344 assert_eq!(pool.queued_pool.len(), 1, "{failure_message}");
2345 }
2346 }
2347 }
2348
2349 fn assert_single_tx_starting_subpool<T: TransactionOrdering>(&self, pool: &TxPool<T>) {
2353 self.assert_subpool_lengths(
2354 pool,
2355 format!("pool length check failed at start of test: {self:?}"),
2356 self.subpool,
2357 );
2358 }
2359
2360 fn assert_single_tx_ending_subpool<T: TransactionOrdering>(&self, pool: &TxPool<T>) {
2364 self.assert_subpool_lengths(
2365 pool,
2366 format!("pool length check failed at end of test: {self:?}"),
2367 self.new_subpool,
2368 );
2369 }
2370 }
2371
2372 #[test]
2373 fn test_promote_blob_tx_with_both_pending_fee_updates() {
2374 let on_chain_balance = U256::MAX;
2377 let on_chain_nonce = 0;
2378 let mut f = MockTransactionFactory::default();
2379 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2380
2381 let max_fee_per_blob_gas = tx.max_fee_per_blob_gas().unwrap();
2382 let max_fee_per_gas = tx.max_fee_per_gas() as u64;
2383
2384 let mut expected_promotions = vec![
2386 PromotionTest {
2387 blobfee: max_fee_per_blob_gas + 1,
2388 basefee: max_fee_per_gas + 1,
2389 subpool: SubPool::Blob,
2390 blobfee_update: max_fee_per_blob_gas + 1,
2391 basefee_update: max_fee_per_gas + 1,
2392 new_subpool: SubPool::Blob,
2393 },
2394 PromotionTest {
2395 blobfee: max_fee_per_blob_gas + 1,
2396 basefee: max_fee_per_gas + 1,
2397 subpool: SubPool::Blob,
2398 blobfee_update: max_fee_per_blob_gas,
2399 basefee_update: max_fee_per_gas + 1,
2400 new_subpool: SubPool::Blob,
2401 },
2402 PromotionTest {
2403 blobfee: max_fee_per_blob_gas + 1,
2404 basefee: max_fee_per_gas + 1,
2405 subpool: SubPool::Blob,
2406 blobfee_update: max_fee_per_blob_gas + 1,
2407 basefee_update: max_fee_per_gas,
2408 new_subpool: SubPool::Blob,
2409 },
2410 PromotionTest {
2411 blobfee: max_fee_per_blob_gas + 1,
2412 basefee: max_fee_per_gas + 1,
2413 subpool: SubPool::Blob,
2414 blobfee_update: max_fee_per_blob_gas,
2415 basefee_update: max_fee_per_gas,
2416 new_subpool: SubPool::Pending,
2417 },
2418 PromotionTest {
2419 blobfee: max_fee_per_blob_gas,
2420 basefee: max_fee_per_gas + 1,
2421 subpool: SubPool::Blob,
2422 blobfee_update: max_fee_per_blob_gas,
2423 basefee_update: max_fee_per_gas,
2424 new_subpool: SubPool::Pending,
2425 },
2426 PromotionTest {
2427 blobfee: max_fee_per_blob_gas + 1,
2428 basefee: max_fee_per_gas,
2429 subpool: SubPool::Blob,
2430 blobfee_update: max_fee_per_blob_gas,
2431 basefee_update: max_fee_per_gas,
2432 new_subpool: SubPool::Pending,
2433 },
2434 PromotionTest {
2435 blobfee: max_fee_per_blob_gas,
2436 basefee: max_fee_per_gas,
2437 subpool: SubPool::Pending,
2438 blobfee_update: max_fee_per_blob_gas,
2439 basefee_update: max_fee_per_gas,
2440 new_subpool: SubPool::Pending,
2441 },
2442 ];
2443
2444 let reversed = expected_promotions.iter().map(|test| test.opposite()).collect::<Vec<_>>();
2446 expected_promotions.extend(reversed);
2447
2448 let expected_promotions = expected_promotions.into_iter().collect::<HashSet<_>>();
2450
2451 for promotion_test in &expected_promotions {
2452 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2453
2454 let mut block_info = pool.block_info();
2456
2457 block_info.pending_blob_fee = Some(promotion_test.blobfee);
2458 block_info.pending_basefee = promotion_test.basefee;
2459 pool.set_block_info(block_info);
2460
2461 let validated = f.validated(tx.clone());
2462 let id = *validated.id();
2463 pool.add_transaction(validated, on_chain_balance, on_chain_nonce, None).unwrap();
2464
2465 promotion_test.assert_single_tx_starting_subpool(&pool);
2467
2468 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2470 assert_eq!(
2471 internal_tx.subpool, promotion_test.subpool,
2472 "Subpools do not match at start of test: {promotion_test:?}"
2473 );
2474
2475 block_info.pending_basefee = promotion_test.basefee_update;
2477 block_info.pending_blob_fee = Some(promotion_test.blobfee_update);
2478 pool.set_block_info(block_info);
2479
2480 let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
2482 assert_eq!(
2483 internal_tx.subpool, promotion_test.new_subpool,
2484 "Subpools do not match at end of test: {promotion_test:?}"
2485 );
2486
2487 promotion_test.assert_single_tx_ending_subpool(&pool);
2489 }
2490 }
2491
2492 #[test]
2493 fn test_insert_pending() {
2494 let on_chain_balance = U256::MAX;
2495 let on_chain_nonce = 0;
2496 let mut f = MockTransactionFactory::default();
2497 let mut pool = AllTransactions::default();
2498 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2499 let valid_tx = f.validated(tx);
2500 let InsertOk { updates, replaced_tx, move_to, state, .. } =
2501 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2502 assert!(updates.is_empty());
2503 assert!(replaced_tx.is_none());
2504 assert!(state.contains(TxState::NO_NONCE_GAPS));
2505 assert!(state.contains(TxState::ENOUGH_BALANCE));
2506 assert_eq!(move_to, SubPool::Pending);
2507
2508 let inserted = pool.txs.get(&valid_tx.transaction_id).unwrap();
2509 assert_eq!(inserted.subpool, SubPool::Pending);
2510 }
2511
2512 #[test]
2513 fn test_simple_insert() {
2514 let on_chain_balance = U256::ZERO;
2515 let on_chain_nonce = 0;
2516 let mut f = MockTransactionFactory::default();
2517 let mut pool = AllTransactions::default();
2518 let mut tx = MockTransaction::eip1559().inc_price().inc_limit();
2519 tx.set_priority_fee(100);
2520 tx.set_max_fee(100);
2521 let valid_tx = f.validated(tx.clone());
2522 let InsertOk { updates, replaced_tx, move_to, state, .. } =
2523 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2524 assert!(updates.is_empty());
2525 assert!(replaced_tx.is_none());
2526 assert!(state.contains(TxState::NO_NONCE_GAPS));
2527 assert!(!state.contains(TxState::ENOUGH_BALANCE));
2528 assert_eq!(move_to, SubPool::Queued);
2529
2530 assert_eq!(pool.len(), 1);
2531 assert!(pool.contains(valid_tx.hash()));
2532 let expected_state = TxState::ENOUGH_FEE_CAP_BLOCK | TxState::NO_NONCE_GAPS;
2533 let inserted = pool.get(valid_tx.id()).unwrap();
2534 assert!(inserted.state.intersects(expected_state));
2535
2536 let res = pool.insert_tx(valid_tx, on_chain_balance, on_chain_nonce);
2538 res.unwrap_err();
2539 assert_eq!(pool.len(), 1);
2540
2541 let valid_tx = f.validated(tx.next());
2542 let InsertOk { updates, replaced_tx, move_to, state, .. } =
2543 pool.insert_tx(valid_tx.clone(), on_chain_balance, on_chain_nonce).unwrap();
2544
2545 assert!(updates.is_empty());
2546 assert!(replaced_tx.is_none());
2547 assert!(state.contains(TxState::NO_NONCE_GAPS));
2548 assert!(!state.contains(TxState::ENOUGH_BALANCE));
2549 assert_eq!(move_to, SubPool::Queued);
2550
2551 assert!(pool.contains(valid_tx.hash()));
2552 assert_eq!(pool.len(), 2);
2553 let inserted = pool.get(valid_tx.id()).unwrap();
2554 assert!(inserted.state.intersects(expected_state));
2555 }
2556
2557 #[test]
2558 fn insert_already_imported() {
2559 let on_chain_balance = U256::ZERO;
2560 let on_chain_nonce = 0;
2561 let mut f = MockTransactionFactory::default();
2562 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2563 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2564 let tx = f.validated(tx);
2565 pool.add_transaction(tx.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
2566 match pool.add_transaction(tx, on_chain_balance, on_chain_nonce, None).unwrap_err().kind {
2567 PoolErrorKind::AlreadyImported => {}
2568 _ => unreachable!(),
2569 }
2570 }
2571
2572 #[test]
2573 fn insert_replace() {
2574 let on_chain_balance = U256::ZERO;
2575 let on_chain_nonce = 0;
2576 let mut f = MockTransactionFactory::default();
2577 let mut pool = AllTransactions::default();
2578 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2579 let first = f.validated(tx.clone());
2580 let _ = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2581 let replacement = f.validated(tx.rng_hash().inc_price());
2582 let InsertOk { updates, replaced_tx, .. } =
2583 pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap();
2584 assert!(updates.is_empty());
2585 let replaced = replaced_tx.unwrap();
2586 assert_eq!(replaced.0.hash(), first.hash());
2587
2588 assert!(!pool.contains(first.hash()));
2590 assert!(pool.contains(replacement.hash()));
2591 assert_eq!(pool.len(), 1);
2592 }
2593
2594 #[test]
2595 fn insert_replace_txpool() {
2596 let on_chain_balance = U256::ZERO;
2597 let on_chain_nonce = 0;
2598 let mut f = MockTransactionFactory::default();
2599 let mut pool = TxPool::mock();
2600
2601 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2602 let first = f.validated(tx.clone());
2603 let first_added =
2604 pool.add_transaction(first, on_chain_balance, on_chain_nonce, None).unwrap();
2605 let replacement = f.validated(tx.rng_hash().inc_price());
2606 let replacement_added = pool
2607 .add_transaction(replacement.clone(), on_chain_balance, on_chain_nonce, None)
2608 .unwrap();
2609
2610 assert!(!pool.contains(first_added.hash()));
2612 assert!(pool.subpool_contains(replacement_added.subpool(), replacement_added.id()));
2614
2615 assert!(pool.contains(replacement.hash()));
2616 let size = pool.size();
2617 assert_eq!(size.total, 1);
2618 size.assert_invariants();
2619 }
2620
2621 #[test]
2622 fn insert_replace_underpriced() {
2623 let on_chain_balance = U256::ZERO;
2624 let on_chain_nonce = 0;
2625 let mut f = MockTransactionFactory::default();
2626 let mut pool = AllTransactions::default();
2627 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2628 let first = f.validated(tx.clone());
2629 let _res = pool.insert_tx(first, on_chain_balance, on_chain_nonce);
2630 let mut replacement = f.validated(tx.rng_hash());
2631 replacement.transaction = replacement.transaction.decr_price();
2632 let err = pool.insert_tx(replacement, on_chain_balance, on_chain_nonce).unwrap_err();
2633 assert!(matches!(err, InsertErr::Underpriced { .. }));
2634 }
2635
2636 #[test]
2637 fn insert_replace_underpriced_not_enough_bump() {
2638 let on_chain_balance = U256::ZERO;
2639 let on_chain_nonce = 0;
2640 let mut f = MockTransactionFactory::default();
2641 let mut pool = AllTransactions::default();
2642 let mut tx = MockTransaction::eip1559().inc_price().inc_limit();
2643 tx.set_priority_fee(100);
2644 tx.set_max_fee(100);
2645 let first = f.validated(tx.clone());
2646 let _ = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2647 let mut replacement = f.validated(tx.rng_hash().inc_price());
2648
2649 replacement.transaction.set_priority_fee(109);
2651 replacement.transaction.set_max_fee(109);
2652 let err =
2653 pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap_err();
2654 assert!(matches!(err, InsertErr::Underpriced { .. }));
2655 assert!(pool.contains(first.hash()));
2657 assert_eq!(pool.len(), 1);
2658
2659 replacement.transaction.set_priority_fee(110);
2661 replacement.transaction.set_max_fee(109);
2662 let err =
2663 pool.insert_tx(replacement.clone(), on_chain_balance, on_chain_nonce).unwrap_err();
2664 assert!(matches!(err, InsertErr::Underpriced { .. }));
2665 assert!(pool.contains(first.hash()));
2666 assert_eq!(pool.len(), 1);
2667
2668 replacement.transaction.set_priority_fee(109);
2670 replacement.transaction.set_max_fee(110);
2671 let err = pool.insert_tx(replacement, on_chain_balance, on_chain_nonce).unwrap_err();
2672 assert!(matches!(err, InsertErr::Underpriced { .. }));
2673 assert!(pool.contains(first.hash()));
2674 assert_eq!(pool.len(), 1);
2675 }
2676
2677 #[test]
2678 fn insert_conflicting_type_normal_to_blob() {
2679 let on_chain_balance = U256::from(10_000);
2680 let on_chain_nonce = 0;
2681 let mut f = MockTransactionFactory::default();
2682 let mut pool = AllTransactions::default();
2683 let tx = MockTransaction::eip1559().inc_price().inc_limit();
2684 let first = f.validated(tx.clone());
2685 pool.insert_tx(first, on_chain_balance, on_chain_nonce).unwrap();
2686 let tx = MockTransaction::eip4844().set_sender(tx.sender()).inc_price_by(100).inc_limit();
2687 let blob = f.validated(tx);
2688 let err = pool.insert_tx(blob, on_chain_balance, on_chain_nonce).unwrap_err();
2689 assert!(matches!(err, InsertErr::TxTypeConflict { .. }), "{err:?}");
2690 }
2691
2692 #[test]
2693 fn insert_conflicting_type_blob_to_normal() {
2694 let on_chain_balance = U256::from(10_000);
2695 let on_chain_nonce = 0;
2696 let mut f = MockTransactionFactory::default();
2697 let mut pool = AllTransactions::default();
2698 let tx = MockTransaction::eip4844().inc_price().inc_limit();
2699 let first = f.validated(tx.clone());
2700 pool.insert_tx(first, on_chain_balance, on_chain_nonce).unwrap();
2701 let tx = MockTransaction::eip1559().set_sender(tx.sender()).inc_price_by(100).inc_limit();
2702 let tx = f.validated(tx);
2703 let err = pool.insert_tx(tx, on_chain_balance, on_chain_nonce).unwrap_err();
2704 assert!(matches!(err, InsertErr::TxTypeConflict { .. }), "{err:?}");
2705 }
2706
2707 #[test]
2709 fn insert_previous() {
2710 let on_chain_balance = U256::ZERO;
2711 let on_chain_nonce = 0;
2712 let mut f = MockTransactionFactory::default();
2713 let mut pool = AllTransactions::default();
2714 let tx = MockTransaction::eip1559().inc_nonce().inc_price().inc_limit();
2715 let first = f.validated(tx.clone());
2716 let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce);
2717
2718 let first_in_pool = pool.get(first.id()).unwrap();
2719
2720 assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2722
2723 let prev = f.validated(tx.prev());
2724 let InsertOk { updates, replaced_tx, state, move_to, .. } =
2725 pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2726
2727 assert!(updates.is_empty());
2729 assert!(replaced_tx.is_none());
2730 assert!(state.contains(TxState::NO_NONCE_GAPS));
2731 assert_eq!(move_to, SubPool::Queued);
2732
2733 let first_in_pool = pool.get(first.id()).unwrap();
2734 assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2736 }
2737
2738 #[test]
2740 fn insert_with_updates() {
2741 let on_chain_balance = U256::from(10_000);
2742 let on_chain_nonce = 0;
2743 let mut f = MockTransactionFactory::default();
2744 let mut pool = AllTransactions::default();
2745 let tx = MockTransaction::eip1559().inc_nonce().set_gas_price(100).inc_limit();
2746 let first = f.validated(tx.clone());
2747 let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce).unwrap();
2748
2749 let first_in_pool = pool.get(first.id()).unwrap();
2750 assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2752 assert_eq!(SubPool::Queued, first_in_pool.subpool);
2753
2754 let prev = f.validated(tx.prev());
2755 let InsertOk { updates, replaced_tx, state, move_to, .. } =
2756 pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2757
2758 assert_eq!(updates.len(), 1);
2760 assert!(replaced_tx.is_none());
2761 assert!(state.contains(TxState::NO_NONCE_GAPS));
2762 assert_eq!(move_to, SubPool::Pending);
2763
2764 let first_in_pool = pool.get(first.id()).unwrap();
2765 assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2767 assert_eq!(SubPool::Pending, first_in_pool.subpool);
2768 }
2769
2770 #[test]
2771 fn insert_previous_blocking() {
2772 let on_chain_balance = U256::from(1_000);
2773 let on_chain_nonce = 0;
2774 let mut f = MockTransactionFactory::default();
2775 let mut pool = AllTransactions::default();
2776 pool.pending_fees.base_fee = pool.minimal_protocol_basefee.checked_add(1).unwrap();
2777 let tx = MockTransaction::eip1559().inc_nonce().inc_limit();
2778 let first = f.validated(tx.clone());
2779
2780 let _res = pool.insert_tx(first.clone(), on_chain_balance, on_chain_nonce);
2781
2782 let first_in_pool = pool.get(first.id()).unwrap();
2783
2784 assert!(tx.get_gas_price() < pool.pending_fees.base_fee as u128);
2785 assert!(!first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2787
2788 let prev = f.validated(tx.prev());
2789 let InsertOk { updates, replaced_tx, state, move_to, .. } =
2790 pool.insert_tx(prev, on_chain_balance, on_chain_nonce).unwrap();
2791
2792 assert!(!state.contains(TxState::ENOUGH_FEE_CAP_BLOCK));
2793 assert!(updates.is_empty());
2795 assert!(replaced_tx.is_none());
2796 assert!(state.contains(TxState::NO_NONCE_GAPS));
2797 assert_eq!(move_to, SubPool::BaseFee);
2798
2799 let first_in_pool = pool.get(first.id()).unwrap();
2800 assert!(first_in_pool.state.contains(TxState::NO_NONCE_GAPS));
2802 }
2803
2804 #[test]
2805 fn rejects_spammer() {
2806 let on_chain_balance = U256::from(1_000);
2807 let on_chain_nonce = 0;
2808 let mut f = MockTransactionFactory::default();
2809 let mut pool = AllTransactions::default();
2810
2811 let mut tx = MockTransaction::eip1559();
2812 let unblocked_tx = tx.clone();
2813 for _ in 0..pool.max_account_slots {
2814 tx = tx.next();
2815 pool.insert_tx(f.validated(tx.clone()), on_chain_balance, on_chain_nonce).unwrap();
2816 }
2817
2818 assert_eq!(
2819 pool.max_account_slots,
2820 pool.tx_count(f.ids.sender_id(tx.get_sender()).unwrap())
2821 );
2822
2823 let err =
2824 pool.insert_tx(f.validated(tx.next()), on_chain_balance, on_chain_nonce).unwrap_err();
2825 assert!(matches!(err, InsertErr::ExceededSenderTransactionsCapacity { .. }));
2826
2827 assert!(pool
2828 .insert_tx(f.validated(unblocked_tx), on_chain_balance, on_chain_nonce)
2829 .is_ok());
2830 }
2831
2832 #[test]
2833 fn allow_local_spamming() {
2834 let on_chain_balance = U256::from(1_000);
2835 let on_chain_nonce = 0;
2836 let mut f = MockTransactionFactory::default();
2837 let mut pool = AllTransactions::default();
2838
2839 let mut tx = MockTransaction::eip1559();
2840 for _ in 0..pool.max_account_slots {
2841 tx = tx.next();
2842 pool.insert_tx(
2843 f.validated_with_origin(TransactionOrigin::Local, tx.clone()),
2844 on_chain_balance,
2845 on_chain_nonce,
2846 )
2847 .unwrap();
2848 }
2849
2850 assert_eq!(
2851 pool.max_account_slots,
2852 pool.tx_count(f.ids.sender_id(tx.get_sender()).unwrap())
2853 );
2854
2855 pool.insert_tx(
2856 f.validated_with_origin(TransactionOrigin::Local, tx.next()),
2857 on_chain_balance,
2858 on_chain_nonce,
2859 )
2860 .unwrap();
2861 }
2862
2863 #[test]
2864 fn reject_tx_over_gas_limit() {
2865 let on_chain_balance = U256::from(1_000);
2866 let on_chain_nonce = 0;
2867 let mut f = MockTransactionFactory::default();
2868 let mut pool = AllTransactions::default();
2869
2870 let tx = MockTransaction::eip1559().with_gas_limit(30_000_001);
2871
2872 assert!(matches!(
2873 pool.insert_tx(f.validated(tx), on_chain_balance, on_chain_nonce),
2874 Err(InsertErr::TxGasLimitMoreThanAvailableBlockGas { .. })
2875 ));
2876 }
2877
2878 #[test]
2879 fn test_tx_equal_gas_limit() {
2880 let on_chain_balance = U256::from(1_000);
2881 let on_chain_nonce = 0;
2882 let mut f = MockTransactionFactory::default();
2883 let mut pool = AllTransactions::default();
2884
2885 let tx = MockTransaction::eip1559().with_gas_limit(30_000_000);
2886
2887 let InsertOk { state, .. } =
2888 pool.insert_tx(f.validated(tx), on_chain_balance, on_chain_nonce).unwrap();
2889 assert!(state.contains(TxState::NOT_TOO_MUCH_GAS));
2890 }
2891
2892 #[test]
2893 fn update_basefee_subpools() {
2894 let mut f = MockTransactionFactory::default();
2895 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2896
2897 let tx = MockTransaction::eip1559().inc_price_by(10);
2898 let validated = f.validated(tx.clone());
2899 let id = *validated.id();
2900 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
2901
2902 assert_eq!(pool.pending_pool.len(), 1);
2903
2904 pool.update_basefee((tx.max_fee_per_gas() + 1) as u64);
2905
2906 assert!(pool.pending_pool.is_empty());
2907 assert_eq!(pool.basefee_pool.len(), 1);
2908
2909 assert_eq!(pool.all_transactions.txs.get(&id).unwrap().subpool, SubPool::BaseFee)
2910 }
2911
2912 #[test]
2913 fn update_basefee_subpools_setting_block_info() {
2914 let mut f = MockTransactionFactory::default();
2915 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2916
2917 let tx = MockTransaction::eip1559().inc_price_by(10);
2918 let validated = f.validated(tx.clone());
2919 let id = *validated.id();
2920 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
2921
2922 assert_eq!(pool.pending_pool.len(), 1);
2923
2924 let mut block_info = pool.block_info();
2926 block_info.pending_basefee = (tx.max_fee_per_gas() + 1) as u64;
2927 pool.set_block_info(block_info);
2928
2929 assert!(pool.pending_pool.is_empty());
2930 assert_eq!(pool.basefee_pool.len(), 1);
2931
2932 assert_eq!(pool.all_transactions.txs.get(&id).unwrap().subpool, SubPool::BaseFee)
2933 }
2934
2935 #[test]
2936 fn get_highest_transaction_by_sender_and_nonce() {
2937 let mut f = MockTransactionFactory::default();
2939 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
2940
2941 let tx = MockTransaction::eip1559();
2943 pool.add_transaction(f.validated(tx.clone()), U256::from(1_000), 0, None).unwrap();
2944
2945 let tx1 = tx.inc_price().next();
2947
2948 let tx1_validated = f.validated(tx1.clone());
2950 pool.add_transaction(tx1_validated, U256::from(1_000), 0, None).unwrap();
2951
2952 assert_eq!(
2954 pool.get_highest_nonce_by_sender(f.ids.sender_id(&tx.sender()).unwrap()),
2955 Some(1)
2956 );
2957
2958 let highest_tx = pool
2960 .get_highest_transaction_by_sender(f.ids.sender_id(&tx.sender()).unwrap())
2961 .expect("Failed to retrieve highest transaction");
2962
2963 assert_eq!(highest_tx.as_ref().transaction, tx1);
2965 }
2966
2967 #[test]
2968 fn get_highest_consecutive_transaction_by_sender() {
2969 let mut pool = TxPool::new(MockOrdering::default(), PoolConfig::default());
2971 let mut f = MockTransactionFactory::default();
2972
2973 let sender = Address::random();
2975 let txs: Vec<_> = vec![0, 1, 2, 4, 5, 8, 9];
2976 for nonce in txs {
2977 let mut mock_tx = MockTransaction::eip1559();
2978 mock_tx.set_sender(sender);
2979 mock_tx.set_nonce(nonce);
2980
2981 let validated_tx = f.validated(mock_tx);
2982 pool.add_transaction(validated_tx, U256::from(1000), 0, None).unwrap();
2983 }
2984
2985 let sender_id = f.ids.sender_id(&sender).unwrap();
2987 let next_tx =
2988 pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(0));
2989 assert_eq!(next_tx.map(|tx| tx.nonce()), Some(2), "Expected nonce 2 for on-chain nonce 0");
2990
2991 let next_tx =
2992 pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(4));
2993 assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 4");
2994
2995 let next_tx =
2996 pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5));
2997 assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 5");
2998
2999 let mut info = SenderInfo::default();
3001 info.update(8, U256::ZERO);
3002 pool.sender_info.insert(sender_id, info);
3003 let next_tx =
3004 pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5));
3005 assert_eq!(next_tx.map(|tx| tx.nonce()), Some(9), "Expected nonce 9 for on-chain nonce 8");
3006 }
3007
3008 #[test]
3009 fn discard_nonce_too_low() {
3010 let mut f = MockTransactionFactory::default();
3011 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3012
3013 let tx = MockTransaction::eip1559().inc_price_by(10);
3014 let validated = f.validated(tx.clone());
3015 let id = *validated.id();
3016 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3017
3018 let next = tx.next();
3019 let validated = f.validated(next.clone());
3020 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3021
3022 assert_eq!(pool.pending_pool.len(), 2);
3023
3024 let mut changed_senders = HashMap::default();
3025 changed_senders.insert(
3026 id.sender,
3027 SenderInfo { state_nonce: next.nonce(), balance: U256::from(1_000) },
3028 );
3029 let outcome = pool.update_accounts(changed_senders);
3030 assert_eq!(outcome.discarded.len(), 1);
3031 assert_eq!(pool.pending_pool.len(), 1);
3032 }
3033
3034 #[test]
3035 fn discard_with_large_blob_txs() {
3036 reth_tracing::init_test_tracing();
3038
3039 let mut f = MockTransactionFactory::default();
3041 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3042 let default_limits = pool.config.blob_limit;
3043
3044 let a_sender = address!("0x000000000000000000000000000000000000000a");
3047
3048 let mut block_info = pool.block_info();
3050 block_info.pending_blob_fee = Some(100);
3051 block_info.pending_basefee = 100;
3052
3053 pool.set_block_info(block_info);
3055
3056 let a_txs = MockTransactionSet::dependent(a_sender, 0, 2, TxType::Eip4844)
3058 .into_iter()
3059 .map(|mut tx| {
3060 tx.set_size(default_limits.max_size / 2 + 1);
3061 tx.set_max_fee((block_info.pending_basefee - 1).into());
3062 tx
3063 })
3064 .collect::<Vec<_>>();
3065
3066 for tx in a_txs {
3068 pool.add_transaction(f.validated(tx), U256::from(1_000), 0, None).unwrap();
3069 }
3070
3071 let removed = pool.discard_worst();
3073 assert_eq!(removed.len(), 1);
3074 }
3075
3076 #[test]
3077 fn discard_with_parked_large_txs() {
3078 reth_tracing::init_test_tracing();
3080
3081 let mut f = MockTransactionFactory::default();
3083 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3084 let default_limits = pool.config.queued_limit;
3085
3086 let a_sender = address!("0x000000000000000000000000000000000000000a");
3089
3090 let pool_base_fee = 100;
3092 pool.update_basefee(pool_base_fee);
3093
3094 let a_txs = MockTransactionSet::dependent(a_sender, 0, 3, TxType::Eip1559)
3096 .into_iter()
3097 .map(|mut tx| {
3098 tx.set_size(default_limits.max_size / 2 + 1);
3099 tx.set_max_fee((pool_base_fee - 1).into());
3100 tx
3101 })
3102 .collect::<Vec<_>>();
3103
3104 for tx in a_txs {
3106 pool.add_transaction(f.validated(tx), U256::from(1_000), 0, None).unwrap();
3107 }
3108
3109 let removed = pool.discard_worst();
3111 assert_eq!(removed.len(), 1);
3112 }
3113
3114 #[test]
3115 fn discard_at_capacity() {
3116 let mut f = MockTransactionFactory::default();
3117 let queued_limit = SubPoolLimit::new(1000, usize::MAX);
3118 let mut pool =
3119 TxPool::new(MockOrdering::default(), PoolConfig { queued_limit, ..Default::default() });
3120
3121 for _ in 0..queued_limit.max_txs {
3123 let tx = MockTransaction::eip1559().inc_price_by(10).inc_nonce();
3124 let validated = f.validated(tx.clone());
3125 let _id = *validated.id();
3126 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3127 }
3128
3129 let size = pool.size();
3130 assert_eq!(size.queued, queued_limit.max_txs);
3131
3132 for _ in 0..queued_limit.max_txs {
3133 let tx = MockTransaction::eip1559().inc_price_by(10).inc_nonce();
3134 let validated = f.validated(tx.clone());
3135 let _id = *validated.id();
3136 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3137
3138 pool.discard_worst();
3139 pool.assert_invariants();
3140 assert!(pool.size().queued <= queued_limit.max_txs);
3141 }
3142 }
3143
3144 #[test]
3145 fn discard_blobs_at_capacity() {
3146 let mut f = MockTransactionFactory::default();
3147 let blob_limit = SubPoolLimit::new(1000, usize::MAX);
3148 let mut pool =
3149 TxPool::new(MockOrdering::default(), PoolConfig { blob_limit, ..Default::default() });
3150 pool.all_transactions.pending_fees.blob_fee = 10000;
3151 for _ in 0..blob_limit.max_txs {
3153 let tx = MockTransaction::eip4844().inc_price_by(100).with_blob_fee(100);
3154 let validated = f.validated(tx.clone());
3155 let _id = *validated.id();
3156 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3157 }
3158
3159 let size = pool.size();
3160 assert_eq!(size.blob, blob_limit.max_txs);
3161
3162 for _ in 0..blob_limit.max_txs {
3163 let tx = MockTransaction::eip4844().inc_price_by(100).with_blob_fee(100);
3164 let validated = f.validated(tx.clone());
3165 let _id = *validated.id();
3166 pool.add_transaction(validated, U256::from(1_000), 0, None).unwrap();
3167
3168 pool.discard_worst();
3169 pool.assert_invariants();
3170 assert!(pool.size().blob <= blob_limit.max_txs);
3171 }
3172 }
3173
3174 #[test]
3175 fn account_updates_sender_balance() {
3176 let mut on_chain_balance = U256::from(100);
3177 let on_chain_nonce = 0;
3178 let mut f = MockTransactionFactory::default();
3179 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3180
3181 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3182 let tx_1 = tx_0.next();
3183 let tx_2 = tx_1.next();
3184
3185 let v0 = f.validated(tx_0);
3187 let v1 = f.validated(tx_1);
3188 let v2 = f.validated(tx_2);
3189
3190 let _res =
3191 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3192 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3193 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce, None).unwrap();
3194
3195 assert_eq!(1, pool.pending_transactions().len());
3197 assert_eq!(2, pool.queued_transactions().len());
3198
3199 let mut updated_accounts = HashMap::default();
3201 on_chain_balance = U256::from(300);
3202 updated_accounts.insert(
3203 v0.sender_id(),
3204 SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
3205 );
3206 pool.update_accounts(updated_accounts.clone());
3207
3208 assert_eq!(3, pool.pending_transactions().len());
3209 assert!(pool.queued_transactions().is_empty());
3210
3211 updated_accounts.entry(v0.sender_id()).and_modify(|v| v.balance = U256::from(1));
3213 pool.update_accounts(updated_accounts);
3214
3215 assert!(pool.pending_transactions().is_empty());
3216 assert_eq!(3, pool.queued_transactions().len());
3217 }
3218
3219 #[test]
3220 fn account_updates_nonce_gap() {
3221 let on_chain_balance = U256::from(10_000);
3222 let mut on_chain_nonce = 0;
3223 let mut f = MockTransactionFactory::default();
3224 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3225
3226 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3227 let tx_1 = tx_0.next();
3228 let tx_2 = tx_1.next();
3229
3230 let v0 = f.validated(tx_0);
3232 let v1 = f.validated(tx_1);
3233 let v2 = f.validated(tx_2);
3234
3235 let _res =
3237 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3238 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3239
3240 assert!(pool.queued_transactions().is_empty());
3241 assert_eq!(2, pool.pending_transactions().len());
3242
3243 pool.remove_transaction_by_hash(v0.hash());
3245
3246 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce, None).unwrap();
3248
3249 assert_eq!(2, pool.queued_transactions().len());
3251 assert!(pool.pending_transactions().is_empty());
3252
3253 let mut updated_accounts = HashMap::default();
3255 on_chain_nonce += 1;
3256 updated_accounts.insert(
3257 v0.sender_id(),
3258 SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
3259 );
3260 pool.update_accounts(updated_accounts);
3261
3262 assert!(pool.queued_transactions().is_empty());
3264 assert_eq!(2, pool.pending_transactions().len());
3265 }
3266 #[test]
3267 fn test_transaction_removal() {
3268 let on_chain_balance = U256::from(10_000);
3269 let on_chain_nonce = 0;
3270 let mut f = MockTransactionFactory::default();
3271 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3272
3273 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3274 let tx_1 = tx_0.next();
3275
3276 let v0 = f.validated(tx_0);
3278 let v1 = f.validated(tx_1);
3279
3280 let _res =
3282 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3283 let _res =
3284 pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3285
3286 assert_eq!(0, pool.queued_transactions().len());
3287 assert_eq!(2, pool.pending_transactions().len());
3288
3289 pool.remove_transaction(v0.id());
3291 let pool_txs = pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>();
3293 assert_eq!(vec![v1.nonce()], pool_txs);
3294 }
3295 #[test]
3296 fn test_remove_transactions() {
3297 let on_chain_balance = U256::from(10_000);
3298 let on_chain_nonce = 0;
3299 let mut f = MockTransactionFactory::default();
3300 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3301
3302 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3303 let tx_1 = tx_0.next();
3304 let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3305 let tx_3 = tx_2.next();
3306
3307 let v0 = f.validated(tx_0);
3309 let v1 = f.validated(tx_1);
3310 let v2 = f.validated(tx_2);
3311 let v3 = f.validated(tx_3);
3312
3313 let _res =
3315 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3316 let _res =
3317 pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3318 let _res =
3319 pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3320 let _res =
3321 pool.add_transaction(v3.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3322
3323 assert_eq!(0, pool.queued_transactions().len());
3324 assert_eq!(4, pool.pending_transactions().len());
3325
3326 pool.remove_transactions(vec![*v0.hash(), *v2.hash()]);
3327
3328 assert_eq!(2, pool.queued_transactions().len());
3329 assert!(pool.pending_transactions().is_empty());
3330 assert!(pool.contains(v1.hash()));
3331 assert!(pool.contains(v3.hash()));
3332 }
3333
3334 #[test]
3335 fn test_remove_transactions_middle_pending_hash() {
3336 let on_chain_balance = U256::from(10_000);
3337 let on_chain_nonce = 0;
3338 let mut f = MockTransactionFactory::default();
3339 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3340
3341 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3342 let tx_1 = tx_0.next();
3343 let tx_2 = tx_1.next();
3344 let tx_3 = tx_2.next();
3345
3346 let v0 = f.validated(tx_0);
3348 let v1 = f.validated(tx_1);
3349 let v2 = f.validated(tx_2);
3350 let v3 = f.validated(tx_3);
3351
3352 let _res = pool.add_transaction(v0, on_chain_balance, on_chain_nonce, None).unwrap();
3354 let _res =
3355 pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3356 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce, None).unwrap();
3357 let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce, None).unwrap();
3358
3359 assert_eq!(0, pool.queued_transactions().len());
3360 assert_eq!(4, pool.pending_transactions().len());
3361
3362 let mut removed_txs = pool.remove_transactions(vec![*v1.hash()]);
3363 assert_eq!(1, removed_txs.len());
3364
3365 assert_eq!(2, pool.queued_transactions().len());
3366 assert_eq!(1, pool.pending_transactions().len());
3367
3368 let removed_tx = removed_txs.pop().unwrap();
3370 let v1 = f.validated(removed_tx.transaction.clone());
3371 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3372 assert_eq!(0, pool.queued_transactions().len());
3373 assert_eq!(4, pool.pending_transactions().len());
3374 }
3375
3376 #[test]
3377 fn test_remove_transactions_and_descendants() {
3378 let on_chain_balance = U256::from(10_000);
3379 let on_chain_nonce = 0;
3380 let mut f = MockTransactionFactory::default();
3381 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3382
3383 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3384 let tx_1 = tx_0.next();
3385 let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3386 let tx_3 = tx_2.next();
3387 let tx_4 = tx_3.next();
3388
3389 let v0 = f.validated(tx_0);
3391 let v1 = f.validated(tx_1);
3392 let v2 = f.validated(tx_2);
3393 let v3 = f.validated(tx_3);
3394 let v4 = f.validated(tx_4);
3395
3396 let _res =
3398 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3399 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3400 let _res =
3401 pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3402 let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce, None).unwrap();
3403 let _res = pool.add_transaction(v4, on_chain_balance, on_chain_nonce, None).unwrap();
3404
3405 assert_eq!(0, pool.queued_transactions().len());
3406 assert_eq!(5, pool.pending_transactions().len());
3407
3408 pool.remove_transactions_and_descendants(vec![*v0.hash(), *v2.hash()]);
3409
3410 assert_eq!(0, pool.queued_transactions().len());
3411 assert_eq!(0, pool.pending_transactions().len());
3412 }
3413 #[test]
3414 fn test_remove_descendants() {
3415 let on_chain_balance = U256::from(10_000);
3416 let on_chain_nonce = 0;
3417 let mut f = MockTransactionFactory::default();
3418 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3419
3420 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3421 let tx_1 = tx_0.next();
3422 let tx_2 = tx_1.next();
3423 let tx_3 = tx_2.next();
3424
3425 let v0 = f.validated(tx_0);
3427 let v1 = f.validated(tx_1);
3428 let v2 = f.validated(tx_2);
3429 let v3 = f.validated(tx_3);
3430
3431 let _res =
3433 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3434 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3435 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce, None).unwrap();
3436 let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce, None).unwrap();
3437
3438 assert_eq!(0, pool.queued_transactions().len());
3439 assert_eq!(4, pool.pending_transactions().len());
3440
3441 let mut removed = Vec::new();
3442 pool.remove_transaction(v0.id());
3443 pool.remove_descendants(v0.id(), &mut removed);
3444
3445 assert_eq!(0, pool.queued_transactions().len());
3446 assert_eq!(0, pool.pending_transactions().len());
3447 assert_eq!(3, removed.len());
3448 }
3449 #[test]
3450 fn test_remove_transactions_by_sender() {
3451 let on_chain_balance = U256::from(10_000);
3452 let on_chain_nonce = 0;
3453 let mut f = MockTransactionFactory::default();
3454 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3455
3456 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3457 let tx_1 = tx_0.next();
3458 let tx_2 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3459 let tx_3 = tx_2.next();
3460 let tx_4 = tx_3.next();
3461
3462 let v0 = f.validated(tx_0);
3464 let v1 = f.validated(tx_1);
3465 let v2 = f.validated(tx_2);
3466 let v3 = f.validated(tx_3);
3467 let v4 = f.validated(tx_4);
3468
3469 let _res =
3471 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3472 let _res =
3473 pool.add_transaction(v1.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3474 let _res =
3475 pool.add_transaction(v2.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3476 let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce, None).unwrap();
3477 let _res = pool.add_transaction(v4, on_chain_balance, on_chain_nonce, None).unwrap();
3478
3479 assert_eq!(0, pool.queued_transactions().len());
3480 assert_eq!(5, pool.pending_transactions().len());
3481
3482 pool.remove_transactions_by_sender(v2.sender_id());
3483
3484 assert_eq!(0, pool.queued_transactions().len());
3485 assert_eq!(2, pool.pending_transactions().len());
3486 assert!(pool.contains(v0.hash()));
3487 assert!(pool.contains(v1.hash()));
3488 }
3489 #[test]
3490 fn wrong_best_order_of_transactions() {
3491 let on_chain_balance = U256::from(10_000);
3492 let mut on_chain_nonce = 0;
3493 let mut f = MockTransactionFactory::default();
3494 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3495
3496 let tx_0 = MockTransaction::eip1559().set_gas_price(100).inc_limit();
3497 let tx_1 = tx_0.next();
3498 let tx_2 = tx_1.next();
3499 let tx_3 = tx_2.next();
3500
3501 let v0 = f.validated(tx_0);
3503 let v1 = f.validated(tx_1);
3504 let v2 = f.validated(tx_2);
3505 let v3 = f.validated(tx_3);
3506
3507 let _res =
3509 pool.add_transaction(v0.clone(), on_chain_balance, on_chain_nonce, None).unwrap();
3510 let _res = pool.add_transaction(v1, on_chain_balance, on_chain_nonce, None).unwrap();
3511
3512 assert_eq!(0, pool.queued_transactions().len());
3513 assert_eq!(2, pool.pending_transactions().len());
3514
3515 pool.remove_transaction(v0.id());
3517
3518 let _res = pool.add_transaction(v2, on_chain_balance, on_chain_nonce, None).unwrap();
3520
3521 assert_eq!(1, pool.queued_transactions().len());
3523 assert_eq!(1, pool.pending_transactions().len());
3524
3525 let mut updated_accounts = HashMap::default();
3527 on_chain_nonce += 1;
3528 updated_accounts.insert(
3529 v0.sender_id(),
3530 SenderInfo { state_nonce: on_chain_nonce, balance: on_chain_balance },
3531 );
3532 pool.update_accounts(updated_accounts);
3533
3534 assert_eq!(0, pool.queued_transactions().len());
3537 assert_eq!(2, pool.pending_transactions().len());
3538
3539 let _res = pool.add_transaction(v3, on_chain_balance, on_chain_nonce, None).unwrap();
3541 assert_eq!(0, pool.queued_transactions().len());
3542 assert_eq!(3, pool.pending_transactions().len());
3543
3544 assert_eq!(
3547 pool.best_transactions().map(|x| x.id().nonce).collect::<Vec<_>>(),
3548 vec![1, 2, 3]
3549 );
3550 }
3551
3552 #[test]
3553 fn test_best_with_attributes() {
3554 let on_chain_balance = U256::MAX;
3555 let on_chain_nonce = 0;
3556 let mut f = MockTransactionFactory::default();
3557 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3558
3559 let base_fee: u128 = 100;
3560 let blob_fee: u128 = 100;
3561
3562 let mut block_info = pool.block_info();
3564 block_info.pending_basefee = base_fee as u64;
3565 block_info.pending_blob_fee = Some(blob_fee);
3566 pool.set_block_info(block_info);
3567
3568 let tx1 = MockTransaction::eip4844()
3570 .with_sender(Address::with_last_byte(1))
3571 .with_max_fee(base_fee + 10)
3572 .with_blob_fee(blob_fee + 10);
3573 let tx2 = MockTransaction::eip4844()
3574 .with_sender(Address::with_last_byte(2))
3575 .with_max_fee(base_fee + 10)
3576 .with_blob_fee(blob_fee);
3577 let tx3 = MockTransaction::eip4844()
3578 .with_sender(Address::with_last_byte(3))
3579 .with_max_fee(base_fee)
3580 .with_blob_fee(blob_fee + 10);
3581 let tx4 = MockTransaction::eip4844()
3582 .with_sender(Address::with_last_byte(4))
3583 .with_max_fee(base_fee)
3584 .with_blob_fee(blob_fee);
3585 let tx5 = MockTransaction::eip4844()
3586 .with_sender(Address::with_last_byte(5))
3587 .with_max_fee(base_fee)
3588 .with_blob_fee(blob_fee - 10);
3589 let tx6 = MockTransaction::eip4844()
3590 .with_sender(Address::with_last_byte(6))
3591 .with_max_fee(base_fee - 10)
3592 .with_blob_fee(blob_fee);
3593 let tx7 = MockTransaction::eip4844()
3594 .with_sender(Address::with_last_byte(7))
3595 .with_max_fee(base_fee - 10)
3596 .with_blob_fee(blob_fee - 10);
3597
3598 for tx in vec![
3599 tx1.clone(),
3600 tx2.clone(),
3601 tx3.clone(),
3602 tx4.clone(),
3603 tx5.clone(),
3604 tx6.clone(),
3605 tx7.clone(),
3606 ] {
3607 pool.add_transaction(f.validated(tx.clone()), on_chain_balance, on_chain_nonce, None)
3608 .unwrap();
3609 }
3610
3611 let base_fee = base_fee as u64;
3612 let blob_fee = blob_fee as u64;
3613
3614 let cases = vec![
3615 (BestTransactionsAttributes::new(base_fee + 5, Some(blob_fee + 5)), vec![tx1.clone()]),
3617 (
3619 BestTransactionsAttributes::new(base_fee + 5, Some(blob_fee)),
3620 vec![tx1.clone(), tx2.clone()],
3621 ),
3622 (
3624 BestTransactionsAttributes::new(base_fee + 5, Some(blob_fee - 5)),
3625 vec![tx1.clone(), tx2.clone()],
3626 ),
3627 (
3629 BestTransactionsAttributes::new(base_fee, Some(blob_fee + 5)),
3630 vec![tx1.clone(), tx3.clone()],
3631 ),
3632 (
3634 BestTransactionsAttributes::new(base_fee, Some(blob_fee)),
3635 vec![tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()],
3636 ),
3637 (
3639 BestTransactionsAttributes::new(base_fee, Some(blob_fee - 10)),
3640 vec![tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone(), tx5.clone()],
3641 ),
3642 (
3644 BestTransactionsAttributes::new(base_fee - 5, Some(blob_fee + 5)),
3645 vec![tx1.clone(), tx3.clone()],
3646 ),
3647 (
3649 BestTransactionsAttributes::new(base_fee - 10, Some(blob_fee)),
3650 vec![tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone(), tx6.clone()],
3651 ),
3652 (
3654 BestTransactionsAttributes::new(base_fee - 10, Some(blob_fee - 10)),
3655 vec![tx1, tx2, tx5, tx3, tx4, tx6, tx7],
3656 ),
3657 ];
3658
3659 for (idx, (attribute, expected)) in cases.into_iter().enumerate() {
3660 let mut best = pool.best_transactions_with_attributes(attribute);
3661
3662 for (tx_idx, expected_tx) in expected.into_iter().enumerate() {
3663 let tx = best.next().expect("Transaction should be returned");
3664 assert_eq!(
3665 tx.transaction,
3666 expected_tx,
3667 "Failed tx {} in case {}",
3668 tx_idx + 1,
3669 idx + 1
3670 );
3671 }
3672
3673 assert!(best.next().is_none());
3675 }
3676 }
3677
3678 #[test]
3679 fn test_pending_ordering() {
3680 let mut f = MockTransactionFactory::default();
3681 let mut pool = TxPool::new(MockOrdering::default(), Default::default());
3682
3683 let tx_0 = MockTransaction::eip1559().with_nonce(1).set_gas_price(100).inc_limit();
3684 let tx_1 = tx_0.next();
3685
3686 let v0 = f.validated(tx_0);
3687 let v1 = f.validated(tx_1);
3688
3689 pool.add_transaction(v0.clone(), U256::MAX, 0, None).unwrap();
3691 assert_eq!(1, pool.queued_transactions().len());
3692
3693 pool.add_transaction(v1, U256::MAX, 1, None).unwrap();
3695
3696 assert_eq!(2, pool.pending_transactions().len());
3697 assert_eq!(0, pool.queued_transactions().len());
3698
3699 assert_eq!(
3700 pool.pending_pool.independent().get(&v0.sender_id()).unwrap().transaction.nonce(),
3701 v0.nonce()
3702 );
3703 }
3704
3705 #[test]
3707 fn one_sender_one_independent_transaction() {
3708 let mut on_chain_balance = U256::from(4_999); let mut on_chain_nonce = 40;
3710 let mut f = MockTransactionFactory::default();
3711 let mut pool = TxPool::mock();
3712 let mut submitted_txs = Vec::new();
3713
3714 let template =
3716 MockTransaction::eip1559().inc_price().inc_limit().with_value(U256::from(1_001));
3717
3718 for tx_nonce in 40..48 {
3721 let tx = f.validated(template.clone().with_nonce(tx_nonce).rng_hash());
3722 submitted_txs.push(*tx.id());
3723 pool.add_transaction(tx, on_chain_balance, on_chain_nonce, None).unwrap();
3724 }
3725
3726 on_chain_balance = U256::from(999_999);
3729 on_chain_nonce = 42;
3730 pool.remove_transaction(&submitted_txs[0]);
3731 pool.remove_transaction(&submitted_txs[1]);
3732
3733 for tx_nonce in 48..52 {
3735 pool.add_transaction(
3736 f.validated(template.clone().with_nonce(tx_nonce).rng_hash()),
3737 on_chain_balance,
3738 on_chain_nonce,
3739 None,
3740 )
3741 .unwrap();
3742 }
3743
3744 let best_txs: Vec<_> = pool.pending().best().map(|tx| *tx.id()).collect();
3745 assert_eq!(best_txs.len(), 10); assert_eq!(pool.pending_pool.independent().len(), 1);
3748 }
3749}