Skip to main content

reth_transaction_pool/
lib.rs

1//! Reth's transaction pool implementation.
2//!
3//! This crate provides a generic transaction pool implementation.
4//!
5//! ## Functionality
6//!
7//! The transaction pool is responsible for
8//!
9//!    - recording incoming transactions
10//!    - providing existing transactions
11//!    - ordering and providing the best transactions for block production
12//!    - monitoring memory footprint and enforce pool size limits
13//!    - storing blob data for transactions in a separate blobstore on insertion
14//!
15//! ## Transaction Flow: From Network/RPC to Pool
16//!
17//! Transactions enter the pool through two main paths:
18//!
19//! ### 1. Network Path (P2P)
20//!
21//! ```text
22//! Network Peer
23//!     ↓
24//! Transactions or NewPooledTransactionHashes message
25//!     ↓
26//! TransactionsManager (crates/net/network/src/transactions/mod.rs)
27//!     │
28//!     ├─→ For Transactions message:
29//!     │   ├─→ Validates message format
30//!     │   ├─→ Checks if transaction already known
31//!     │   ├─→ Marks peer as having seen the transaction
32//!     │   └─→ Queues for import
33//!     │
34//!     └─→ For NewPooledTransactionHashes message:
35//!         ├─→ Filters out already known transactions
36//!         ├─→ Queues unknown hashes for fetching
37//!         ├─→ Sends GetPooledTransactions request
38//!         ├─→ Receives PooledTransactions response
39//!         └─→ Queues fetched transactions for import
40//!             ↓
41//! pool.add_external_transactions() [Origin: External]
42//!     ↓
43//! Transaction Validation & Pool Addition
44//! ```
45//!
46//! ### 2. RPC Path (Local submission)
47//!
48//! ```text
49//! eth_sendRawTransaction RPC call
50//!     ├─→ Decodes raw bytes
51//!     └─→ Recovers sender
52//!         ↓
53//! pool.add_transaction() [Origin: Local]
54//!     ↓
55//! Transaction Validation & Pool Addition
56//! ```
57//!
58//! ### Transaction Origins
59//!
60//! - **Local**: Transactions submitted via RPC (trusted, may have different fee requirements)
61//! - **External**: Transactions from network peers (untrusted, subject to stricter validation)
62//! - **Private**: Local transactions that should not be propagated to the network
63//!
64//! ## Validation Process
65//!
66//! ### Stateless Checks
67//!
68//! Ethereum transactions undergo several stateless checks:
69//!
70//! - **Transaction Type**: Fork-dependent support (Legacy always, EIP-2930/1559/4844/7702 need
71//!   activation)
72//! - **Size**: Input data ≤ 128KB (default)
73//! - **Gas**: Limit ≤ block gas limit
74//! - **Fees**: Priority fee ≤ max fee; local tx fee cap; external minimum priority fee
75//! - **Chain ID**: Must match current chain
76//! - **Intrinsic Gas**: Sufficient for data and access lists
77//! - **Blobs** (EIP-4844): Valid count, KZG proofs
78//!
79//! ### Stateful Checks
80//!
81//! 1. **Sender**: No bytecode (unless EIP-7702 delegated in Prague)
82//! 2. **Nonce**: ≥ account nonce
83//! 3. **Balance**: Covers value + (`gas_limit` × `max_fee_per_gas`)
84//!
85//! ### Common Errors
86//!
87//! - [`NonceNotConsistent`](reth_primitives_traits::transaction::error::InvalidTransactionError::NonceNotConsistent): Nonce too low
88//! - [`InsufficientFunds`](reth_primitives_traits::transaction::error::InvalidTransactionError::InsufficientFunds): Insufficient balance
89//! - [`ExceedsGasLimit`](crate::error::InvalidPoolTransactionError::ExceedsGasLimit): Gas limit too
90//!   high
91//! - [`SignerAccountHasBytecode`](reth_primitives_traits::transaction::error::InvalidTransactionError::SignerAccountHasBytecode): EOA has code
92//! - [`Underpriced`](crate::error::InvalidPoolTransactionError::Underpriced): Fee too low
93//! - [`ReplacementUnderpriced`](crate::error::PoolErrorKind::ReplacementUnderpriced): Replacement
94//!   transaction fee too low
95//! - Blob errors:
96//!   - [`MissingEip4844BlobSidecar`](crate::error::Eip4844PoolTransactionError::MissingEip4844BlobSidecar): Missing sidecar
97//!   - [`InvalidEip4844Blob`](crate::error::Eip4844PoolTransactionError::InvalidEip4844Blob):
98//!     Invalid blob proofs
99//!   - [`NoEip4844Blobs`](crate::error::Eip4844PoolTransactionError::NoEip4844Blobs): EIP-4844
100//!     transaction without blobs
101//!   - [`TooManyEip4844Blobs`](crate::error::Eip4844PoolTransactionError::TooManyEip4844Blobs): Too
102//!     many blobs
103//!
104//! ## Subpool Design
105//!
106//! The pool maintains four distinct subpools, each serving a specific purpose
107//!
108//! ### Subpools
109//!
110//! 1. **Pending**: Ready for inclusion (no gaps, sufficient balance/fees)
111//! 2. **Queued**: Future transactions (nonce gaps or insufficient balance)
112//! 3. **`BaseFee`**: Valid but below current base fee
113//! 4. **Blob**: EIP-4844 transactions not pending due to insufficient base fee or blob fee
114//!
115//! ### State Transitions
116//!
117//! Transactions move between subpools based on state changes:
118//!
119//! ```text
120//! Queued ─────────→ BaseFee/Blob ────────→ Pending
121//!   ↑                      ↑                       │
122//!   │                      │                       │
123//!   └────────────────────┴─────────────────────┘
124//!         (demotions due to state changes)
125//! ```
126//!
127//! **Promotions**: Nonce gaps filled, balance/fee improvements
128//! **Demotions**: Nonce gaps created, balance/fee degradation
129//!
130//! ## Pool Maintenance
131//!
132//! 1. **Block Updates**: Removes mined txs, updates accounts/fees, triggers movements
133//! 2. **Size Enforcement**: Discards worst transactions when limits exceeded
134//! 3. **Propagation**: External (always), Local (configurable), Private (never)
135//!
136//! ## Assumptions
137//!
138//! ### Transaction type
139//!
140//! The pool expects certain ethereum related information from the generic transaction type of the
141//! pool ([`PoolTransaction`]), this includes gas price, base fee (EIP-1559 transactions), nonce
142//! etc. It makes no assumptions about the encoding format, but the transaction type must report its
143//! size so pool size limits (memory) can be enforced.
144//!
145//! ### Transaction ordering
146//!
147//! The pending pool contains transactions that can be mined on the current state.
148//! The order in which they're returned are determined by a `Priority` value returned by the
149//! `TransactionOrdering` type this pool is configured with.
150//!
151//! This is only used in the _pending_ pool to yield the best transactions for block production. The
152//! _base pool_ is ordered by base fee, and the _queued pool_ by current distance.
153//!
154//! ### Validation
155//!
156//! The pool itself does not validate incoming transactions, instead this should be provided by
157//! implementing `TransactionsValidator`. Only transactions that the validator returns as valid are
158//! included in the pool. It is assumed that transaction that are in the pool are either valid on
159//! the current state or could become valid after certain state changes. Transactions that can never
160//! become valid (e.g. nonce lower than current on chain nonce) will never be added to the pool and
161//! instead are discarded right away.
162//!
163//! ### State Changes
164//!
165//! New blocks trigger pool updates via changesets (see Pool Maintenance).
166//!
167//! ## Implementation details
168//!
169//! The `TransactionPool` trait exposes all externally used functionality of the pool, such as
170//! inserting, querying specific transactions by hash or retrieving the best transactions.
171//! In addition, it enables the registration of event listeners that are notified of state changes.
172//! Events are communicated via channels.
173//!
174//! ### Architecture
175//!
176//! The final `TransactionPool` is made up of two layers:
177//!
178//! The lowest layer is the actual pool implementations that manages (validated) transactions:
179//! [`TxPool`](crate::pool::txpool::TxPool). This is contained in a higher level pool type that
180//! guards the low level pool and handles additional listeners or metrics: [`PoolInner`].
181//!
182//! The transaction pool will be used by separate consumers (RPC, P2P), to make sharing easier, the
183//! [`Pool`] type is just an `Arc` wrapper around `PoolInner`. This is the usable type that provides
184//! the `TransactionPool` interface.
185//!
186//!
187//! ## Blob Transactions
188//!
189//! Blob transaction can be quite large hence they are stored in a separate blobstore. The pool is
190//! responsible for inserting blob data for new transactions into the blobstore.
191//! See also [`ValidTransaction`](validate::ValidTransaction)
192//!
193//!
194//! ## Examples
195//!
196//! Listen for new transactions and print them:
197//!
198//! ```
199//! use reth_chainspec::MAINNET;
200//! use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
201//! use reth_tasks::Runtime;
202//! use reth_chainspec::ChainSpecProvider;
203//! use reth_transaction_pool::{TransactionValidationTaskExecutor, Pool, TransactionPool};
204//! use reth_transaction_pool::blobstore::InMemoryBlobStore;
205//! use reth_chainspec::EthereumHardforks;
206//! use reth_evm::ConfigureEvm;
207//! use alloy_consensus::Header;
208//! async fn t<C, Evm>(client: C, evm_config: Evm)
209//! where
210//!     C: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory + BlockReaderIdExt<Header = Header> + Clone + 'static,
211//!     Evm: ConfigureEvm<Primitives: reth_primitives_traits::NodePrimitives<BlockHeader = Header>> + 'static,
212//! {
213//!     let blob_store = InMemoryBlobStore::default();
214//!     let runtime = Runtime::test();
215//!     let pool = Pool::eth_pool(
216//!         TransactionValidationTaskExecutor::eth(client, evm_config, blob_store.clone(), runtime),
217//!         blob_store,
218//!         Default::default(),
219//!     );
220//!   let mut transactions = pool.pending_transactions_listener();
221//!   tokio::task::spawn( async move {
222//!      while let Some(tx) = transactions.recv().await {
223//!          println!("New transaction: {:?}", tx);
224//!      }
225//!   });
226//!
227//!   // do something useful with the pool, like RPC integration
228//!
229//! # }
230//! ```
231//!
232//! Spawn maintenance task to keep the pool updated
233//!
234//! ```
235//! use futures_util::Stream;
236//! use reth_chain_state::CanonStateNotification;
237//! use reth_chainspec::{MAINNET, ChainSpecProvider, ChainSpec};
238//! use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
239//! use reth_tasks::Runtime;
240//! use reth_transaction_pool::{TransactionValidationTaskExecutor, Pool};
241//! use reth_transaction_pool::blobstore::InMemoryBlobStore;
242//! use reth_transaction_pool::maintain::{maintain_transaction_pool_future};
243//! use reth_evm::ConfigureEvm;
244//! use reth_ethereum_primitives::EthPrimitives;
245//! use alloy_consensus::Header;
246//!
247//!  async fn t<C, St, Evm>(client: C, stream: St, evm_config: Evm)
248//!    where C: StateProviderFactory + BlockReaderIdExt<Header = Header> + ChainSpecProvider<ChainSpec = ChainSpec> + Clone + 'static,
249//!     St: Stream<Item = CanonStateNotification<EthPrimitives>> + Send + Unpin + 'static,
250//!     Evm: ConfigureEvm<Primitives = EthPrimitives> + 'static,
251//!     {
252//!     let blob_store = InMemoryBlobStore::default();
253//!     let runtime = Runtime::test();
254//!     let pool = Pool::eth_pool(
255//!         TransactionValidationTaskExecutor::eth(client.clone(), evm_config, blob_store.clone(), runtime.clone()),
256//!         blob_store,
257//!         Default::default(),
258//!     );
259//!
260//!   // spawn a task that listens for new blocks and updates the pool's transactions, mined transactions etc..
261//!   tokio::task::spawn(maintain_transaction_pool_future(client, pool, stream, runtime.clone(), Default::default()));
262//!
263//! # }
264//! ```
265//!
266//! ## Feature Flags
267//!
268//! - `serde` (default): Enable serde support
269//! - `test-utils`: Export utilities for testing
270
271#![doc(
272    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
273    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
274    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
275)]
276#![cfg_attr(docsrs, feature(doc_cfg))]
277#![cfg_attr(not(test), warn(unused_crate_dependencies))]
278
279pub use imbl::OrdMap;
280
281pub use crate::{
282    batcher::{BatchTxProcessor, BatchTxRequest},
283    blobstore::{BlobStore, BlobStoreError},
284    config::{
285        LocalTransactionConfig, PoolConfig, PriceBumpConfig, SubPoolLimit,
286        DEFAULT_MAX_INFLIGHT_DELEGATED_SLOTS, DEFAULT_PRICE_BUMP,
287        DEFAULT_TXPOOL_ADDITIONAL_VALIDATION_TASKS, MAX_NEW_PENDING_TXS_NOTIFICATIONS,
288        REPLACE_BLOB_PRICE_BUMP, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
289        TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
290    },
291    error::{PoolResult, RawPoolTransactionError},
292    ordering::{CoinbaseTipOrdering, Priority, TransactionOrdering},
293    pool::{
294        blob_tx_priority, fee_delta, state::SubPool, AddedTransactionOutcome,
295        AllTransactionsEvents, FullTransactionEvent, NewTransactionEvent, TransactionEvent,
296        TransactionEvents, TransactionListenerKind,
297    },
298    traits::*,
299    validate::{
300        EthTransactionValidator, StatefulValidationFn, StatelessValidationFn,
301        TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator,
302        ValidPoolTransaction,
303    },
304};
305use crate::{identifier::TransactionId, pool::PoolInner};
306use alloy_eips::{
307    eip4844::{BlobAndProofV1, BlobAndProofV2, BlobCellsAndProofsV1},
308    eip7594::BlobTransactionSidecarVariant,
309};
310use alloy_primitives::{map::AddressSet, Address, TxHash, B128, B256, U256};
311use aquamarine as _;
312use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
313use reth_eth_wire_types::HandleMempoolData;
314use reth_evm::ConfigureEvm;
315use reth_evm_ethereum::EthEvmConfig;
316use reth_execution_types::ChangedAccount;
317use reth_primitives_traits::{HeaderTy, Recovered};
318use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
319use std::sync::Arc;
320use tokio::sync::mpsc::Receiver;
321use tracing::{instrument, trace};
322
323pub mod error;
324pub mod maintain;
325pub mod metrics;
326pub mod noop;
327pub mod pool;
328pub mod validate;
329
330pub mod batcher;
331pub mod blobstore;
332mod config;
333pub mod identifier;
334mod ordering;
335mod traits;
336
337#[cfg(any(test, feature = "test-utils"))]
338/// Common test helpers for mocking a pool
339pub mod test_utils;
340
341/// Type alias for default ethereum transaction pool
342pub type EthTransactionPool<Client, S, Evm = EthEvmConfig, T = EthPooledTransaction> = Pool<
343    TransactionValidationTaskExecutor<EthTransactionValidator<Client, T, Evm>>,
344    CoinbaseTipOrdering<T>,
345    S,
346>;
347
348/// A shareable, generic, customizable `TransactionPool` implementation.
349#[derive(Debug)]
350pub struct Pool<V, T: TransactionOrdering, S> {
351    /// Arc'ed instance of the pool internals
352    pool: Arc<PoolInner<V, T, S>>,
353}
354
355// === impl Pool ===
356
357impl<V, T, S> Pool<V, T, S>
358where
359    V: TransactionValidator,
360    T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
361    S: BlobStore,
362{
363    /// Create a new transaction pool instance.
364    pub fn new(validator: V, ordering: T, blob_store: S, config: PoolConfig) -> Self {
365        Self { pool: Arc::new(PoolInner::new(validator, ordering, blob_store, config)) }
366    }
367
368    /// Returns the wrapped pool internals.
369    pub fn inner(&self) -> &PoolInner<V, T, S> {
370        &self.pool
371    }
372
373    /// Get the config the pool was configured with.
374    pub fn config(&self) -> &PoolConfig {
375        self.inner().config()
376    }
377
378    /// Get the validator reference.
379    pub fn validator(&self) -> &V {
380        self.inner().validator()
381    }
382
383    /// Validates the given transaction
384    async fn validate(
385        &self,
386        origin: TransactionOrigin,
387        transaction: V::Transaction,
388    ) -> TransactionValidationOutcome<V::Transaction> {
389        self.pool.validator().validate_transaction(origin, transaction).await
390    }
391
392    /// Number of transactions in the entire pool
393    pub fn len(&self) -> usize {
394        self.pool.len()
395    }
396
397    /// Whether the pool is empty
398    pub fn is_empty(&self) -> bool {
399        self.pool.is_empty()
400    }
401
402    /// Returns whether or not the pool is over its configured size and transaction count limits.
403    pub fn is_exceeded(&self) -> bool {
404        self.pool.is_exceeded()
405    }
406
407    /// Returns the configured blob store.
408    pub fn blob_store(&self) -> &S {
409        self.pool.blob_store()
410    }
411}
412
413impl<Client, S, Evm> EthTransactionPool<Client, S, Evm>
414where
415    Client: ChainSpecProvider<ChainSpec: EthereumHardforks>
416        + StateProviderFactory
417        + Clone
418        + BlockReaderIdExt<Header = HeaderTy<Evm::Primitives>>
419        + 'static,
420    S: BlobStore,
421    Evm: ConfigureEvm + 'static,
422{
423    /// Returns a new [`Pool`] that uses the default [`TransactionValidationTaskExecutor`] when
424    /// validating [`EthPooledTransaction`]s and ords via [`CoinbaseTipOrdering`]
425    ///
426    /// # Example
427    ///
428    /// ```
429    /// use reth_chainspec::MAINNET;
430    /// use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
431    /// use reth_tasks::Runtime;
432    /// use reth_chainspec::ChainSpecProvider;
433    /// use reth_transaction_pool::{
434    ///     blobstore::InMemoryBlobStore, Pool, TransactionValidationTaskExecutor,
435    /// };
436    /// use reth_chainspec::EthereumHardforks;
437    /// use reth_evm::ConfigureEvm;
438    /// use alloy_consensus::Header;
439    /// # fn t<C, Evm>(client: C, evm_config: Evm, runtime: Runtime)
440    /// # where
441    /// #     C: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory + BlockReaderIdExt<Header = Header> + Clone + 'static,
442    /// #     Evm: ConfigureEvm<Primitives: reth_primitives_traits::NodePrimitives<BlockHeader = Header>> + 'static,
443    /// # {
444    /// let blob_store = InMemoryBlobStore::default();
445    /// let pool = Pool::eth_pool(
446    ///     TransactionValidationTaskExecutor::eth(
447    ///         client,
448    ///         evm_config,
449    ///         blob_store.clone(),
450    ///         runtime,
451    ///     ),
452    ///     blob_store,
453    ///     Default::default(),
454    /// );
455    /// # }
456    /// ```
457    pub fn eth_pool(
458        validator: TransactionValidationTaskExecutor<
459            EthTransactionValidator<Client, EthPooledTransaction, Evm>,
460        >,
461        blob_store: S,
462        config: PoolConfig,
463    ) -> Self {
464        Self::new(validator, CoinbaseTipOrdering::default(), blob_store, config)
465    }
466}
467
468/// implements the `TransactionPool` interface for various transaction pool API consumers.
469impl<V, T, S> TransactionPool for Pool<V, T, S>
470where
471    V: TransactionValidator,
472    <V as TransactionValidator>::Transaction: EthPoolTransaction,
473    T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
474    S: BlobStore + Clone,
475{
476    type Transaction = T::Transaction;
477
478    fn pool_size(&self) -> PoolSize {
479        self.pool.size()
480    }
481
482    fn block_info(&self) -> BlockInfo {
483        self.pool.block_info()
484    }
485
486    async fn add_transaction_and_subscribe(
487        &self,
488        origin: TransactionOrigin,
489        transaction: Self::Transaction,
490    ) -> PoolResult<TransactionEvents> {
491        let tx = self.validate(origin, transaction).await;
492        self.pool.add_transaction_and_subscribe(origin, tx)
493    }
494
495    async fn add_transaction(
496        &self,
497        origin: TransactionOrigin,
498        transaction: Self::Transaction,
499    ) -> PoolResult<AddedTransactionOutcome> {
500        let tx = self.validate(origin, transaction).await;
501        let mut results = self.pool.add_transactions(origin, std::iter::once(tx));
502        results.pop().expect("result length is the same as the input")
503    }
504
505    async fn add_transactions(
506        &self,
507        origin: TransactionOrigin,
508        transactions: Vec<Self::Transaction>,
509    ) -> Vec<PoolResult<AddedTransactionOutcome>> {
510        if transactions.is_empty() {
511            return Vec::new()
512        }
513        let validated = self
514            .pool
515            .validator()
516            .validate_transactions(transactions.into_iter().map(|tx| (origin, tx)))
517            .await;
518        self.pool.add_transactions(origin, validated)
519    }
520
521    async fn add_transactions_with_origins(
522        &self,
523        transactions: Vec<(TransactionOrigin, Self::Transaction)>,
524    ) -> Vec<PoolResult<AddedTransactionOutcome>> {
525        if transactions.is_empty() {
526            return Vec::new()
527        }
528        let origins: Vec<_> = transactions.iter().map(|(origin, _)| *origin).collect();
529        let validated = self.pool.validator().validate_transactions(transactions).await;
530        self.pool.add_transactions_with_origins(origins.into_iter().zip(validated))
531    }
532
533    fn transaction_event_listener(&self, tx_hash: TxHash) -> Option<TransactionEvents> {
534        self.pool.add_transaction_event_listener(tx_hash)
535    }
536
537    fn all_transactions_event_listener(&self) -> AllTransactionsEvents<Self::Transaction> {
538        self.pool.add_all_transactions_event_listener()
539    }
540
541    fn pending_transactions_listener_for(&self, kind: TransactionListenerKind) -> Receiver<TxHash> {
542        self.pool.add_pending_listener(kind)
543    }
544
545    fn blob_transaction_sidecars_listener(&self) -> Receiver<NewBlobSidecar> {
546        self.pool.add_blob_sidecar_listener()
547    }
548
549    fn new_transactions_listener_for(
550        &self,
551        kind: TransactionListenerKind,
552    ) -> Receiver<NewTransactionEvent<Self::Transaction>> {
553        self.pool.add_new_transaction_listener(kind)
554    }
555
556    fn pooled_transaction_hashes(&self) -> Vec<TxHash> {
557        self.pool.pooled_transactions_hashes()
558    }
559
560    fn pooled_transaction_hashes_max(&self, max: usize) -> Vec<TxHash> {
561        self.pool.pooled_transactions_hashes_max(max)
562    }
563
564    fn pooled_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
565        self.pool.pooled_transactions()
566    }
567
568    fn pooled_transactions_max(
569        &self,
570        max: usize,
571    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
572        self.pool.pooled_transactions_max(max)
573    }
574
575    fn get_pooled_transaction_elements(
576        &self,
577        tx_hashes: Vec<TxHash>,
578        limit: GetPooledTransactionLimit,
579    ) -> Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled> {
580        self.pool.get_pooled_transaction_elements(tx_hashes, limit)
581    }
582
583    fn append_pooled_transaction_elements(
584        &self,
585        tx_hashes: &[TxHash],
586        limit: GetPooledTransactionLimit,
587        out: &mut Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>,
588    ) {
589        self.pool.append_pooled_transaction_elements(tx_hashes, limit, out)
590    }
591
592    fn get_pooled_transaction_element(
593        &self,
594        tx_hash: TxHash,
595    ) -> Option<Recovered<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>>
596    {
597        self.pool.get_pooled_transaction_element(tx_hash)
598    }
599
600    fn best_transactions(
601        &self,
602    ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
603        Box::new(self.pool.best_transactions())
604    }
605
606    fn best_transactions_with_attributes(
607        &self,
608        best_transactions_attributes: BestTransactionsAttributes,
609    ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
610        self.pool.best_transactions_with_attributes(best_transactions_attributes)
611    }
612
613    fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
614        self.pool.pending_transactions()
615    }
616
617    fn get_pending_transaction_by_sender_and_nonce(
618        &self,
619        sender: Address,
620        nonce: u64,
621    ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
622        self.pool.get_pending_transaction_by_sender_and_nonce(sender, nonce)
623    }
624
625    fn pending_transactions_max(
626        &self,
627        max: usize,
628    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
629        self.pool.pending_transactions_max(max)
630    }
631
632    fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
633        self.pool.queued_transactions()
634    }
635
636    fn pending_and_queued_txn_count(&self) -> (usize, usize) {
637        let data = self.pool.get_pool_data();
638        let pending = data.pending_transactions_count();
639        let queued = data.queued_transactions_count();
640        (pending, queued)
641    }
642
643    fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction> {
644        self.pool.all_transactions()
645    }
646
647    fn all_transaction_hashes(&self) -> Vec<TxHash> {
648        self.pool.all_transaction_hashes()
649    }
650
651    fn remove_transactions(
652        &self,
653        hashes: Vec<TxHash>,
654    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
655        self.pool.remove_transactions(hashes)
656    }
657
658    fn remove_transactions_and_descendants(
659        &self,
660        hashes: Vec<TxHash>,
661    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
662        self.pool.remove_transactions_and_descendants(hashes)
663    }
664
665    fn remove_transactions_by_sender(
666        &self,
667        sender: Address,
668    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
669        self.pool.remove_transactions_by_sender(sender)
670    }
671
672    fn prune_transactions(
673        &self,
674        hashes: Vec<TxHash>,
675    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
676        self.pool.prune_transactions(hashes)
677    }
678
679    fn retain_unknown<A>(&self, announcement: &mut A)
680    where
681        A: HandleMempoolData,
682    {
683        self.pool.retain_unknown(announcement)
684    }
685
686    fn retain_contains<A>(&self, announcement: &mut A)
687    where
688        A: HandleMempoolData,
689    {
690        self.pool.retain_contains(announcement)
691    }
692
693    fn get(&self, tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
694        self.inner().get(tx_hash)
695    }
696
697    fn get_all(&self, txs: Vec<TxHash>) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
698        self.inner().get_all(txs)
699    }
700
701    fn on_propagated(&self, txs: PropagatedTransactions) {
702        self.inner().on_propagated(txs)
703    }
704
705    fn get_transactions_by_sender(
706        &self,
707        sender: Address,
708    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
709        self.pool.get_transactions_by_sender(sender)
710    }
711
712    fn get_pending_transactions_with_predicate(
713        &self,
714        predicate: impl FnMut(&ValidPoolTransaction<Self::Transaction>) -> bool,
715    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
716        self.pool.pending_transactions_with_predicate(predicate)
717    }
718
719    fn get_pending_transactions_by_sender(
720        &self,
721        sender: Address,
722    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
723        self.pool.get_pending_transactions_by_sender(sender)
724    }
725
726    fn get_queued_transactions_by_sender(
727        &self,
728        sender: Address,
729    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
730        self.pool.get_queued_transactions_by_sender(sender)
731    }
732
733    fn get_highest_transaction_by_sender(
734        &self,
735        sender: Address,
736    ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
737        self.pool.get_highest_transaction_by_sender(sender)
738    }
739
740    fn get_highest_consecutive_transaction_by_sender(
741        &self,
742        sender: Address,
743        on_chain_nonce: u64,
744    ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
745        self.pool.get_highest_consecutive_transaction_by_sender(sender, on_chain_nonce)
746    }
747
748    fn get_transaction_by_sender_and_nonce(
749        &self,
750        sender: Address,
751        nonce: u64,
752    ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
753        let sender_id = self.pool.sender_id(&sender)?;
754        let transaction_id = TransactionId::new(sender_id, nonce);
755
756        self.inner().get_pool_data().all().get(&transaction_id).map(|tx| tx.transaction.clone())
757    }
758
759    fn get_transactions_by_origin(
760        &self,
761        origin: TransactionOrigin,
762    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
763        self.pool.get_transactions_by_origin(origin)
764    }
765
766    /// Returns all pending transactions filtered by [`TransactionOrigin`]
767    fn get_pending_transactions_by_origin(
768        &self,
769        origin: TransactionOrigin,
770    ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
771        self.pool.get_pending_transactions_by_origin(origin)
772    }
773
774    fn unique_senders(&self) -> AddressSet {
775        self.pool.unique_senders()
776    }
777
778    fn get_blob(
779        &self,
780        tx_hash: TxHash,
781    ) -> Result<Option<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
782        self.pool.blob_store().get(tx_hash)
783    }
784
785    fn get_all_blobs(
786        &self,
787        tx_hashes: Vec<TxHash>,
788    ) -> Result<Vec<(TxHash, Arc<BlobTransactionSidecarVariant>)>, BlobStoreError> {
789        self.pool.blob_store().get_all(tx_hashes)
790    }
791
792    fn get_all_blobs_exact(
793        &self,
794        tx_hashes: Vec<TxHash>,
795    ) -> Result<Vec<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
796        self.pool.blob_store().get_exact(tx_hashes)
797    }
798
799    fn get_blobs_for_versioned_hashes_v1(
800        &self,
801        versioned_hashes: &[B256],
802    ) -> Result<Vec<Option<BlobAndProofV1>>, BlobStoreError> {
803        self.pool.blob_store().get_by_versioned_hashes_v1(versioned_hashes)
804    }
805
806    fn get_blobs_for_versioned_hashes_v2(
807        &self,
808        versioned_hashes: &[B256],
809    ) -> Result<Option<Vec<BlobAndProofV2>>, BlobStoreError> {
810        self.pool.blob_store().get_by_versioned_hashes_v2(versioned_hashes)
811    }
812
813    fn get_blobs_for_versioned_hashes_v3(
814        &self,
815        versioned_hashes: &[B256],
816    ) -> Result<Vec<Option<BlobAndProofV2>>, BlobStoreError> {
817        self.pool.blob_store().get_by_versioned_hashes_v3(versioned_hashes)
818    }
819
820    fn get_blobs_for_versioned_hashes_v4(
821        &self,
822        versioned_hashes: &[B256],
823        indices_bitarray: B128,
824    ) -> Result<Vec<Option<BlobCellsAndProofsV1>>, BlobStoreError> {
825        self.pool.blob_store().get_by_versioned_hashes_v4(versioned_hashes, indices_bitarray)
826    }
827
828    fn blob_store(&self) -> Box<dyn BlobStore> {
829        Box::new(self.pool.blob_store().clone())
830    }
831}
832
833impl<V, T, S> TransactionPoolExt for Pool<V, T, S>
834where
835    V: TransactionValidator,
836    <V as TransactionValidator>::Transaction: EthPoolTransaction,
837    T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
838    S: BlobStore + Clone,
839{
840    type Block = V::Block;
841
842    #[instrument(skip(self), target = "txpool")]
843    fn set_block_info(&self, info: BlockInfo) {
844        trace!(target: "txpool", "updating pool block info");
845        self.pool.set_block_info(info)
846    }
847
848    fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, Self::Block>) {
849        self.pool.on_canonical_state_change(update);
850    }
851
852    fn update_accounts(&self, accounts: Vec<ChangedAccount>) {
853        self.pool.update_accounts(accounts);
854    }
855
856    fn delete_blob(&self, tx: TxHash) {
857        self.pool.delete_blob(tx)
858    }
859
860    fn delete_blobs(&self, txs: Vec<TxHash>) {
861        self.pool.delete_blobs(txs)
862    }
863
864    fn cleanup_blobs(&self) {
865        self.pool.cleanup_blobs()
866    }
867}
868
869impl<V, T, S> ValidatingPool for Pool<V, T, S>
870where
871    V: TransactionValidator,
872    <V as TransactionValidator>::Transaction: EthPoolTransaction,
873    T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
874    S: BlobStore + Clone,
875{
876    type Validator = V;
877
878    fn validator(&self) -> &Self::Validator {
879        self.inner().validator()
880    }
881}
882
883impl<V, T: TransactionOrdering, S> Clone for Pool<V, T, S> {
884    fn clone(&self) -> Self {
885        Self { pool: Arc::clone(&self.pool) }
886    }
887}