From df12fee965e6b93f077a7240ed8a4fec6355397b Mon Sep 17 00:00:00 2001 From: Minhyuk Kim Date: Tue, 3 Feb 2026 23:13:52 +0900 Subject: [PATCH] feat(txpool): add `is_transaction_ready` to `TransactionPool` trait (#21742) Co-authored-by: Matthias Seitz Co-authored-by: Amp --- crates/transaction-pool/src/lib.rs | 8 ++++++++ crates/transaction-pool/src/pool/mod.rs | 10 ++++++++++ crates/transaction-pool/src/pool/txpool.rs | 12 ++++++++++++ crates/transaction-pool/src/traits.rs | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/crates/transaction-pool/src/lib.rs b/crates/transaction-pool/src/lib.rs index 37904e9d65..e9cdbb8ae8 100644 --- a/crates/transaction-pool/src/lib.rs +++ b/crates/transaction-pool/src/lib.rs @@ -610,6 +610,14 @@ where self.pool.pending_transactions() } + fn get_pending_transaction_by_sender_and_nonce( + &self, + sender: Address, + nonce: u64, + ) -> Option>> { + self.pool.get_pending_transaction_by_sender_and_nonce(sender, nonce) + } + fn pending_transactions_max( &self, max: usize, diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 07f5085a00..a8655f9368 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -1090,6 +1090,16 @@ where self.get_pool_data().get_transactions_by_sender(sender_id) } + /// Returns a pending transaction sent by the given sender with the given nonce. + pub fn get_pending_transaction_by_sender_and_nonce( + &self, + sender: Address, + nonce: u64, + ) -> Option>> { + let sender_id = self.get_sender_id(sender); + self.get_pool_data().get_pending_transaction_by_sender_and_nonce(sender_id, nonce) + } + /// Returns all queued transactions of the address by sender pub fn get_queued_transactions_by_sender( &self, diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index b9e305f7e4..ee78960b14 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -560,6 +560,18 @@ impl TxPool { self.all_transactions.txs_iter(sender).map(|(_, tx)| Arc::clone(&tx.transaction)).collect() } + /// Returns a pending transaction sent by the given sender with the given nonce. + pub(crate) fn get_pending_transaction_by_sender_and_nonce( + &self, + sender: SenderId, + nonce: u64, + ) -> Option>> { + self.all_transactions + .txs_iter(sender) + .find(|(id, tx)| id.nonce == nonce && tx.subpool == SubPool::Pending) + .map(|(_, tx)| Arc::clone(&tx.transaction)) + } + /// Updates only the pending fees without triggering subpool updates. /// Returns the previous base fee and blob fee values. const fn update_pending_fees_only( diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 24acfcac2d..b4a780bdf5 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -405,6 +405,16 @@ pub trait TransactionPool: Clone + Debug + Send + Sync { /// Consumer: RPC fn pending_transactions(&self) -> Vec>>; + /// Returns a pending transaction if it exists and is ready for immediate execution + /// (i.e., has the lowest nonce among the sender's pending transactions). + fn get_pending_transaction_by_sender_and_nonce( + &self, + sender: Address, + nonce: u64, + ) -> Option>> { + self.best_transactions().find(|tx| tx.sender() == sender && tx.nonce() == nonce) + } + /// Returns first `max` transactions that can be included in the next block. /// See ///