diff --git a/bin/reth/src/args/txpool_args.rs b/bin/reth/src/args/txpool_args.rs index 9a4843d2c9..40912c209e 100644 --- a/bin/reth/src/args/txpool_args.rs +++ b/bin/reth/src/args/txpool_args.rs @@ -65,6 +65,10 @@ impl TxPoolArgs { max_txs: self.queued_max_count, max_size: self.queued_max_size * 1024 * 1024, }, + blob_limit: SubPoolLimit { + max_txs: self.queued_max_count, + max_size: self.queued_max_size * 1024 * 1024, + }, max_account_slots: self.max_account_slots, price_bumps: PriceBumpConfig { default_price_bump: self.price_bump, diff --git a/crates/transaction-pool/src/config.rs b/crates/transaction-pool/src/config.rs index fae1911361..de9cebe639 100644 --- a/crates/transaction-pool/src/config.rs +++ b/crates/transaction-pool/src/config.rs @@ -26,6 +26,8 @@ pub struct PoolConfig { pub basefee_limit: SubPoolLimit, /// Max number of transaction in the queued sub-pool pub queued_limit: SubPoolLimit, + /// Max number of transactions in the blob sub-pool + pub blob_limit: SubPoolLimit, /// Max number of executable transaction slots guaranteed per account pub max_account_slots: usize, /// Price bump (in %) for the transaction pool underpriced check. @@ -41,6 +43,7 @@ impl Default for PoolConfig { pending_limit: Default::default(), basefee_limit: Default::default(), queued_limit: Default::default(), + blob_limit: Default::default(), max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER, price_bumps: Default::default(), local_transactions_config: Default::default(), diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index e9b5acadbc..bcebb4d695 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -92,8 +92,13 @@ pub struct TxPool { /// Holds all parked transactions that currently violate the dynamic fee requirement but could /// be moved to pending if the base fee changes in their favor (decreases) in future blocks. basefee_pool: ParkedPool>, - /// All blob transactions in the pool - blob_transactions: BlobTransactions, + /// Blob transactions in the pool that are __not pending__. + /// + /// This means they either do not satisfy the dynamic fee requirement or the blob fee + /// requirement. These transactions can be moved to pending if the base fee or blob fee changes + /// in their favor (decreases) in future blocks. The transaction may need both the base fee and + /// blob fee to decrease to become executable. + blob_pool: BlobTransactions, /// All transactions in the pool. all_transactions: AllTransactions, /// Transaction pool metrics @@ -110,7 +115,7 @@ impl TxPool { pending_pool: PendingPool::new(ordering), queued_pool: Default::default(), basefee_pool: Default::default(), - blob_transactions: Default::default(), + blob_pool: Default::default(), all_transactions: AllTransactions::new(&config), config, metrics: Default::default(), @@ -136,8 +141,8 @@ impl TxPool { basefee_size: self.basefee_pool.size(), queued: self.queued_pool.len(), queued_size: self.queued_pool.size(), - blob: self.blob_transactions.len(), - blob_size: self.blob_transactions.size(), + blob: self.blob_pool.len(), + blob_size: self.blob_pool.size(), total: self.all_transactions.len(), } } @@ -182,9 +187,8 @@ impl TxPool { (Ordering::Less, Ordering::Equal) | (_, Ordering::Less) => { // decreased blob fee or base fee: recheck blob pool and promote all that are now // valid - let removed = self - .blob_transactions - .enforce_pending_fees(&self.all_transactions.pending_fees); + let removed = + self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees); for tx in removed { let to = { let tx = @@ -216,9 +220,8 @@ impl TxPool { // decreased blob fee or base fee: recheck blob pool and promote all that are now // valid - let removed = self - .blob_transactions - .enforce_pending_fees(&self.all_transactions.pending_fees); + let removed = + self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees); for tx in removed { let to = { let tx = @@ -355,7 +358,7 @@ impl TxPool { // base fee decreased, we need to move transactions from the basefee pool to the // pending pool and satisfy blob fee transactions as well let unlocked_with_blob = - self.blob_transactions.satisfy_attributes(best_transactions_attributes); + self.blob_pool.satisfy_attributes(best_transactions_attributes); Box::new(self.pending_pool.best_with_unlocked( unlocked_with_blob, @@ -389,7 +392,7 @@ impl TxPool { SubPool::Queued => self.queued_pool.contains(id), SubPool::Pending => self.pending_pool.contains(id), SubPool::BaseFee => self.basefee_pool.contains(id), - SubPool::Blob => self.blob_transactions.contains(id), + SubPool::Blob => self.blob_pool.contains(id), } } @@ -695,7 +698,7 @@ impl TxPool { SubPool::Queued => self.queued_pool.remove_transaction(tx), SubPool::Pending => self.pending_pool.remove_transaction(tx), SubPool::BaseFee => self.basefee_pool.remove_transaction(tx), - SubPool::Blob => self.blob_transactions.remove_transaction(tx), + SubPool::Blob => self.blob_pool.remove_transaction(tx), } } @@ -710,7 +713,7 @@ impl TxPool { SubPool::Pending => self.pending_pool.prune_transaction(tx), SubPool::Queued => self.queued_pool.remove_transaction(tx), SubPool::BaseFee => self.basefee_pool.remove_transaction(tx), - SubPool::Blob => self.blob_transactions.remove_transaction(tx), + SubPool::Blob => self.blob_pool.remove_transaction(tx), } } @@ -756,7 +759,7 @@ impl TxPool { self.basefee_pool.add_transaction(tx); } SubPool::Blob => { - self.blob_transactions.add_transaction(tx); + self.blob_pool.add_transaction(tx); } } } @@ -807,6 +810,7 @@ impl TxPool { self, removed, [ pending_limit => pending_pool, basefee_limit => basefee_pool, + blob_limit => blob_pool, queued_limit => queued_pool ] ); @@ -840,7 +844,7 @@ impl TxPool { self.pending_pool.assert_invariants(); self.basefee_pool.assert_invariants(); self.queued_pool.assert_invariants(); - self.blob_transactions.assert_invariants(); + self.blob_pool.assert_invariants(); } } @@ -1912,7 +1916,7 @@ mod tests { pool.add_transaction(validated, on_chain_balance, on_chain_nonce).unwrap(); // assert pool lengths - assert!(pool.blob_transactions.is_empty()); + assert!(pool.blob_pool.is_empty()); assert_eq!(pool.pending_pool.len(), 1); // check tx state and derived subpool @@ -1930,7 +1934,7 @@ mod tests { assert_eq!(internal_tx.subpool, SubPool::Blob); // make sure the blob transaction was promoted into the pending pool - assert_eq!(pool.blob_transactions.len(), 1); + assert_eq!(pool.blob_pool.len(), 1); assert!(pool.pending_pool.is_empty()); } @@ -1953,7 +1957,7 @@ mod tests { // assert pool lengths assert!(pool.pending_pool.is_empty()); - assert_eq!(pool.blob_transactions.len(), 1); + assert_eq!(pool.blob_pool.len(), 1); // check tx state and derived subpool let internal_tx = pool.all_transactions.txs.get(&id).unwrap(); @@ -1971,7 +1975,7 @@ mod tests { // make sure the blob transaction was promoted into the pending pool assert_eq!(pool.pending_pool.len(), 1); - assert!(pool.blob_transactions.is_empty()); + assert!(pool.blob_pool.is_empty()); } /// A struct representing a txpool promotion test instance @@ -2012,25 +2016,25 @@ mod tests { ) { match check_subpool { SubPool::Blob => { - assert_eq!(pool.blob_transactions.len(), 1, "{failure_message}"); + assert_eq!(pool.blob_pool.len(), 1, "{failure_message}"); assert!(pool.pending_pool.is_empty(), "{failure_message}"); assert!(pool.basefee_pool.is_empty(), "{failure_message}"); assert!(pool.queued_pool.is_empty(), "{failure_message}"); } SubPool::Pending => { - assert!(pool.blob_transactions.is_empty(), "{failure_message}"); + assert!(pool.blob_pool.is_empty(), "{failure_message}"); assert_eq!(pool.pending_pool.len(), 1, "{failure_message}"); assert!(pool.basefee_pool.is_empty(), "{failure_message}"); assert!(pool.queued_pool.is_empty(), "{failure_message}"); } SubPool::BaseFee => { - assert!(pool.blob_transactions.is_empty(), "{failure_message}"); + assert!(pool.blob_pool.is_empty(), "{failure_message}"); assert!(pool.pending_pool.is_empty(), "{failure_message}"); assert_eq!(pool.basefee_pool.len(), 1, "{failure_message}"); assert!(pool.queued_pool.is_empty(), "{failure_message}"); } SubPool::Queued => { - assert!(pool.blob_transactions.is_empty(), "{failure_message}"); + assert!(pool.blob_pool.is_empty(), "{failure_message}"); assert!(pool.pending_pool.is_empty(), "{failure_message}"); assert!(pool.basefee_pool.is_empty(), "{failure_message}"); assert_eq!(pool.queued_pool.len(), 1, "{failure_message}");