diff --git a/crates/transaction-pool/src/lib.rs b/crates/transaction-pool/src/lib.rs index 150e6a7fd9..38c64d2fe2 100644 --- a/crates/transaction-pool/src/lib.rs +++ b/crates/transaction-pool/src/lib.rs @@ -665,6 +665,13 @@ where self.pool.remove_transactions_by_sender(sender) } + fn prune_transactions( + &self, + hashes: Vec, + ) -> Vec>> { + self.pool.prune_transactions(hashes) + } + fn retain_unknown(&self, announcement: &mut A) where A: HandleMempoolData, diff --git a/crates/transaction-pool/src/noop.rs b/crates/transaction-pool/src/noop.rs index d08b5a2c7e..2a64a42044 100644 --- a/crates/transaction-pool/src/noop.rs +++ b/crates/transaction-pool/src/noop.rs @@ -231,6 +231,13 @@ impl TransactionPool for NoopTransactionPool { vec![] } + fn prune_transactions( + &self, + _hashes: Vec, + ) -> Vec>> { + vec![] + } + fn retain_unknown(&self, _announcement: &mut A) where A: HandleMempoolData, diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 0764dfccd2..2bf275fbe8 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -1066,6 +1066,21 @@ where removed } + /// Prunes and returns all matching transactions from the pool. + /// + /// This removes the transactions as if they were mined: descendant transactions are **not** + /// parked and remain eligible for inclusion. + pub fn prune_transactions( + &self, + hashes: Vec, + ) -> Vec>> { + if hashes.is_empty() { + return Vec::new() + } + + self.pool.write().prune_transactions(hashes) + } + /// Removes and returns all transactions that are present in the pool. pub fn retain_unknown(&self, announcement: &mut A) where diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index e29b04c146..40f3e2c64b 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -1041,6 +1041,21 @@ impl TxPool { removed } + /// Prunes and returns all matching transactions from the pool. + /// + /// This uses [`Self::prune_transaction_by_hash`] which does **not** park descendant + /// transactions, so they remain in their current sub-pool and can be included in subsequent + /// blocks. + pub(crate) fn prune_transactions( + &mut self, + hashes: Vec, + ) -> Vec>> { + let txs = + hashes.into_iter().filter_map(|hash| self.prune_transaction_by_hash(&hash)).collect(); + self.update_size_metrics(); + txs + } + /// Remove the transaction from the __entire__ pool. /// /// This includes the total set of transaction and the subpool it currently resides in. diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index cc2e5f3fc4..d28529a3ff 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -496,6 +496,44 @@ pub trait TransactionPool: Clone + Debug + Send + Sync { sender: Address, ) -> Vec>>; + /// Prunes a single transaction from the pool. + /// + /// This is similar to [`Self::remove_transaction`] but treats the transaction as _mined_ + /// rather than discarded. The key difference is that pruning does **not** park descendant + /// transactions: their nonce requirements are considered satisfied, so they remain in whatever + /// sub-pool they currently occupy and can be included in the next block. + /// + /// In contrast, [`Self::remove_transaction`] treats the removal as a discard, which + /// introduces a nonce gap and moves all descendant transactions to the queued (parked) + /// sub-pool. + /// + /// Returns the pruned transaction if it existed in the pool. + /// + /// Consumer: Utility + fn prune_transaction( + &self, + hash: TxHash, + ) -> Option>> { + self.prune_transactions(vec![hash]).pop() + } + + /// Prunes all transactions corresponding to the given hashes from the pool. + /// + /// This behaves like [`Self::prune_transaction`] but for multiple transactions at once. + /// Each transaction is removed as if it was mined: descendant transactions are **not** parked + /// and their nonce requirements are considered satisfied. + /// + /// This is useful for scenarios like Flashblocks where transactions are committed across + /// multiple partial blocks without a canonical state update: previously committed transactions + /// can be pruned so that the best-transactions iterator yields their descendants in the + /// correct priority order. + /// + /// Consumer: Utility + fn prune_transactions( + &self, + hashes: Vec, + ) -> Vec>>; + /// Retains only those hashes that are unknown to the pool. /// In other words, removes all transactions from the given set that are currently present in /// the pool. Returns hashes already known to the pool.