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::TokioTaskExecutor;
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 pool = Pool::eth_pool(
215//! TransactionValidationTaskExecutor::eth(client, evm_config, blob_store.clone(), TokioTaskExecutor::default()),
216//! blob_store,
217//! Default::default(),
218//! );
219//! let mut transactions = pool.pending_transactions_listener();
220//! tokio::task::spawn( async move {
221//! while let Some(tx) = transactions.recv().await {
222//! println!("New transaction: {:?}", tx);
223//! }
224//! });
225//!
226//! // do something useful with the pool, like RPC integration
227//!
228//! # }
229//! ```
230//!
231//! Spawn maintenance task to keep the pool updated
232//!
233//! ```
234//! use futures_util::Stream;
235//! use reth_chain_state::CanonStateNotification;
236//! use reth_chainspec::{MAINNET, ChainSpecProvider, ChainSpec};
237//! use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
238//! use reth_tasks::TokioTaskExecutor;
239//! use reth_tasks::TaskSpawner;
240//! use reth_tasks::Runtime;
241//! use reth_transaction_pool::{TransactionValidationTaskExecutor, Pool};
242//! use reth_transaction_pool::blobstore::InMemoryBlobStore;
243//! use reth_transaction_pool::maintain::{maintain_transaction_pool_future};
244//! use reth_evm::ConfigureEvm;
245//! use reth_ethereum_primitives::EthPrimitives;
246//! use alloy_consensus::Header;
247//!
248//! async fn t<C, St, Evm>(client: C, stream: St, evm_config: Evm)
249//! where C: StateProviderFactory + BlockReaderIdExt<Header = Header> + ChainSpecProvider<ChainSpec = ChainSpec> + Clone + 'static,
250//! St: Stream<Item = CanonStateNotification<EthPrimitives>> + Send + Unpin + 'static,
251//! Evm: ConfigureEvm<Primitives = EthPrimitives> + 'static,
252//! {
253//! let blob_store = InMemoryBlobStore::default();
254//! let rt = tokio::runtime::Runtime::new().unwrap();
255//! let runtime = Runtime::with_existing_handle(rt.handle().clone()).unwrap();
256//! let pool = Pool::eth_pool(
257//! TransactionValidationTaskExecutor::eth(client.clone(), evm_config, blob_store.clone(), runtime.clone()),
258//! blob_store,
259//! Default::default(),
260//! );
261//!
262//! // spawn a task that listens for new blocks and updates the pool's transactions, mined transactions etc..
263//! tokio::task::spawn(maintain_transaction_pool_future(client, pool, stream, runtime.clone(), Default::default()));
264//!
265//! # }
266//! ```
267//!
268//! ## Feature Flags
269//!
270//! - `serde` (default): Enable serde support
271//! - `test-utils`: Export utilities for testing
272
273#![doc(
274 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
275 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
276 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
277)]
278#![cfg_attr(docsrs, feature(doc_cfg))]
279#![cfg_attr(not(test), warn(unused_crate_dependencies))]
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,
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, TransactionValidationOutcome, TransactionValidationTaskExecutor,
301 TransactionValidator, ValidPoolTransaction,
302 },
303};
304use crate::{identifier::TransactionId, pool::PoolInner};
305use alloy_eips::{
306 eip4844::{BlobAndProofV1, BlobAndProofV2},
307 eip7594::BlobTransactionSidecarVariant,
308};
309use alloy_primitives::{map::AddressSet, Address, TxHash, B256, U256};
310use aquamarine as _;
311use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
312use reth_eth_wire_types::HandleMempoolData;
313use reth_evm::ConfigureEvm;
314use reth_evm_ethereum::EthEvmConfig;
315use reth_execution_types::ChangedAccount;
316use reth_primitives_traits::{HeaderTy, Recovered};
317use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
318use std::sync::Arc;
319use tokio::sync::mpsc::Receiver;
320use tracing::{instrument, trace};
321
322pub mod error;
323pub mod maintain;
324pub mod metrics;
325pub mod noop;
326pub mod pool;
327pub mod validate;
328
329pub mod batcher;
330pub mod blobstore;
331mod config;
332pub mod identifier;
333mod ordering;
334mod traits;
335
336#[cfg(any(test, feature = "test-utils"))]
337/// Common test helpers for mocking a pool
338pub mod test_utils;
339
340/// Type alias for default ethereum transaction pool
341pub type EthTransactionPool<Client, S, Evm = EthEvmConfig, T = EthPooledTransaction> = Pool<
342 TransactionValidationTaskExecutor<EthTransactionValidator<Client, T, Evm>>,
343 CoinbaseTipOrdering<T>,
344 S,
345>;
346
347/// A shareable, generic, customizable `TransactionPool` implementation.
348#[derive(Debug)]
349pub struct Pool<V, T: TransactionOrdering, S> {
350 /// Arc'ed instance of the pool internals
351 pool: Arc<PoolInner<V, T, S>>,
352}
353
354// === impl Pool ===
355
356impl<V, T, S> Pool<V, T, S>
357where
358 V: TransactionValidator,
359 T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
360 S: BlobStore,
361{
362 /// Create a new transaction pool instance.
363 pub fn new(validator: V, ordering: T, blob_store: S, config: PoolConfig) -> Self {
364 Self { pool: Arc::new(PoolInner::new(validator, ordering, blob_store, config)) }
365 }
366
367 /// Returns the wrapped pool internals.
368 pub fn inner(&self) -> &PoolInner<V, T, S> {
369 &self.pool
370 }
371
372 /// Get the config the pool was configured with.
373 pub fn config(&self) -> &PoolConfig {
374 self.inner().config()
375 }
376
377 /// Get the validator reference.
378 pub fn validator(&self) -> &V {
379 self.inner().validator()
380 }
381
382 /// Validates the given transaction
383 async fn validate(
384 &self,
385 origin: TransactionOrigin,
386 transaction: V::Transaction,
387 ) -> TransactionValidationOutcome<V::Transaction> {
388 self.pool.validator().validate_transaction(origin, transaction).await
389 }
390
391 /// Number of transactions in the entire pool
392 pub fn len(&self) -> usize {
393 self.pool.len()
394 }
395
396 /// Whether the pool is empty
397 pub fn is_empty(&self) -> bool {
398 self.pool.is_empty()
399 }
400
401 /// Returns whether or not the pool is over its configured size and transaction count limits.
402 pub fn is_exceeded(&self) -> bool {
403 self.pool.is_exceeded()
404 }
405
406 /// Returns the configured blob store.
407 pub fn blob_store(&self) -> &S {
408 self.pool.blob_store()
409 }
410}
411
412impl<Client, S, Evm> EthTransactionPool<Client, S, Evm>
413where
414 Client: ChainSpecProvider<ChainSpec: EthereumHardforks>
415 + StateProviderFactory
416 + Clone
417 + BlockReaderIdExt<Header = HeaderTy<Evm::Primitives>>
418 + 'static,
419 S: BlobStore,
420 Evm: ConfigureEvm + 'static,
421{
422 /// Returns a new [`Pool`] that uses the default [`TransactionValidationTaskExecutor`] when
423 /// validating [`EthPooledTransaction`]s and ords via [`CoinbaseTipOrdering`]
424 ///
425 /// # Example
426 ///
427 /// ```
428 /// use reth_chainspec::MAINNET;
429 /// use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
430 /// use reth_tasks::TokioTaskExecutor;
431 /// use reth_chainspec::ChainSpecProvider;
432 /// use reth_transaction_pool::{
433 /// blobstore::InMemoryBlobStore, Pool, TransactionValidationTaskExecutor,
434 /// };
435 /// use reth_chainspec::EthereumHardforks;
436 /// use reth_evm::ConfigureEvm;
437 /// use alloy_consensus::Header;
438 /// # fn t<C, Evm>(client: C, evm_config: Evm)
439 /// # where
440 /// # C: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory + BlockReaderIdExt<Header = Header> + Clone + 'static,
441 /// # Evm: ConfigureEvm<Primitives: reth_primitives_traits::NodePrimitives<BlockHeader = Header>> + 'static,
442 /// # {
443 /// let blob_store = InMemoryBlobStore::default();
444 /// let pool = Pool::eth_pool(
445 /// TransactionValidationTaskExecutor::eth(
446 /// client,
447 /// evm_config,
448 /// blob_store.clone(),
449 /// TokioTaskExecutor::default(),
450 /// ),
451 /// blob_store,
452 /// Default::default(),
453 /// );
454 /// # }
455 /// ```
456 pub fn eth_pool(
457 validator: TransactionValidationTaskExecutor<
458 EthTransactionValidator<Client, EthPooledTransaction, Evm>,
459 >,
460 blob_store: S,
461 config: PoolConfig,
462 ) -> Self {
463 Self::new(validator, CoinbaseTipOrdering::default(), blob_store, config)
464 }
465}
466
467/// implements the `TransactionPool` interface for various transaction pool API consumers.
468impl<V, T, S> TransactionPool for Pool<V, T, S>
469where
470 V: TransactionValidator,
471 <V as TransactionValidator>::Transaction: EthPoolTransaction,
472 T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
473 S: BlobStore,
474{
475 type Transaction = T::Transaction;
476
477 fn pool_size(&self) -> PoolSize {
478 self.pool.size()
479 }
480
481 fn block_info(&self) -> BlockInfo {
482 self.pool.block_info()
483 }
484
485 async fn add_transaction_and_subscribe(
486 &self,
487 origin: TransactionOrigin,
488 transaction: Self::Transaction,
489 ) -> PoolResult<TransactionEvents> {
490 let tx = self.validate(origin, transaction).await;
491 self.pool.add_transaction_and_subscribe(origin, tx)
492 }
493
494 async fn add_transaction(
495 &self,
496 origin: TransactionOrigin,
497 transaction: Self::Transaction,
498 ) -> PoolResult<AddedTransactionOutcome> {
499 let tx = self.validate(origin, transaction).await;
500 let mut results = self.pool.add_transactions(origin, std::iter::once(tx));
501 results.pop().expect("result length is the same as the input")
502 }
503
504 async fn add_transactions_with_origins(
505 &self,
506 transactions: impl IntoIterator<Item = (TransactionOrigin, Self::Transaction)> + Send,
507 ) -> Vec<PoolResult<AddedTransactionOutcome>> {
508 let transactions: Vec<_> = transactions.into_iter().collect();
509 if transactions.is_empty() {
510 return Vec::new()
511 }
512 let origins: Vec<_> = transactions.iter().map(|(origin, _)| *origin).collect();
513 let validated = self.pool.validator().validate_transactions(transactions).await;
514 self.pool.add_transactions_with_origins(origins.into_iter().zip(validated))
515 }
516
517 fn transaction_event_listener(&self, tx_hash: TxHash) -> Option<TransactionEvents> {
518 self.pool.add_transaction_event_listener(tx_hash)
519 }
520
521 fn all_transactions_event_listener(&self) -> AllTransactionsEvents<Self::Transaction> {
522 self.pool.add_all_transactions_event_listener()
523 }
524
525 fn pending_transactions_listener_for(&self, kind: TransactionListenerKind) -> Receiver<TxHash> {
526 self.pool.add_pending_listener(kind)
527 }
528
529 fn blob_transaction_sidecars_listener(&self) -> Receiver<NewBlobSidecar> {
530 self.pool.add_blob_sidecar_listener()
531 }
532
533 fn new_transactions_listener_for(
534 &self,
535 kind: TransactionListenerKind,
536 ) -> Receiver<NewTransactionEvent<Self::Transaction>> {
537 self.pool.add_new_transaction_listener(kind)
538 }
539
540 fn pooled_transaction_hashes(&self) -> Vec<TxHash> {
541 self.pool.pooled_transactions_hashes()
542 }
543
544 fn pooled_transaction_hashes_max(&self, max: usize) -> Vec<TxHash> {
545 self.pool.pooled_transactions_hashes_max(max)
546 }
547
548 fn pooled_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
549 self.pool.pooled_transactions()
550 }
551
552 fn pooled_transactions_max(
553 &self,
554 max: usize,
555 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
556 self.pool.pooled_transactions_max(max)
557 }
558
559 fn get_pooled_transaction_elements(
560 &self,
561 tx_hashes: Vec<TxHash>,
562 limit: GetPooledTransactionLimit,
563 ) -> Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled> {
564 self.pool.get_pooled_transaction_elements(tx_hashes, limit)
565 }
566
567 fn append_pooled_transaction_elements(
568 &self,
569 tx_hashes: &[TxHash],
570 limit: GetPooledTransactionLimit,
571 out: &mut Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>,
572 ) {
573 self.pool.append_pooled_transaction_elements(tx_hashes, limit, out)
574 }
575
576 fn get_pooled_transaction_element(
577 &self,
578 tx_hash: TxHash,
579 ) -> Option<Recovered<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>>
580 {
581 self.pool.get_pooled_transaction_element(tx_hash)
582 }
583
584 fn best_transactions(
585 &self,
586 ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
587 Box::new(self.pool.best_transactions())
588 }
589
590 fn best_transactions_with_attributes(
591 &self,
592 best_transactions_attributes: BestTransactionsAttributes,
593 ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
594 self.pool.best_transactions_with_attributes(best_transactions_attributes)
595 }
596
597 fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
598 self.pool.pending_transactions()
599 }
600
601 fn get_pending_transaction_by_sender_and_nonce(
602 &self,
603 sender: Address,
604 nonce: u64,
605 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
606 self.pool.get_pending_transaction_by_sender_and_nonce(sender, nonce)
607 }
608
609 fn pending_transactions_max(
610 &self,
611 max: usize,
612 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
613 self.pool.pending_transactions_max(max)
614 }
615
616 fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
617 self.pool.queued_transactions()
618 }
619
620 fn pending_and_queued_txn_count(&self) -> (usize, usize) {
621 let data = self.pool.get_pool_data();
622 let pending = data.pending_transactions_count();
623 let queued = data.queued_transactions_count();
624 (pending, queued)
625 }
626
627 fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction> {
628 self.pool.all_transactions()
629 }
630
631 fn all_transaction_hashes(&self) -> Vec<TxHash> {
632 self.pool.all_transaction_hashes()
633 }
634
635 fn remove_transactions(
636 &self,
637 hashes: Vec<TxHash>,
638 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
639 self.pool.remove_transactions(hashes)
640 }
641
642 fn remove_transactions_and_descendants(
643 &self,
644 hashes: Vec<TxHash>,
645 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
646 self.pool.remove_transactions_and_descendants(hashes)
647 }
648
649 fn remove_transactions_by_sender(
650 &self,
651 sender: Address,
652 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
653 self.pool.remove_transactions_by_sender(sender)
654 }
655
656 fn prune_transactions(
657 &self,
658 hashes: Vec<TxHash>,
659 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
660 self.pool.prune_transactions(hashes)
661 }
662
663 fn retain_unknown<A>(&self, announcement: &mut A)
664 where
665 A: HandleMempoolData,
666 {
667 self.pool.retain_unknown(announcement)
668 }
669
670 fn get(&self, tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
671 self.inner().get(tx_hash)
672 }
673
674 fn get_all(&self, txs: Vec<TxHash>) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
675 self.inner().get_all(txs)
676 }
677
678 fn on_propagated(&self, txs: PropagatedTransactions) {
679 self.inner().on_propagated(txs)
680 }
681
682 fn get_transactions_by_sender(
683 &self,
684 sender: Address,
685 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
686 self.pool.get_transactions_by_sender(sender)
687 }
688
689 fn get_pending_transactions_with_predicate(
690 &self,
691 predicate: impl FnMut(&ValidPoolTransaction<Self::Transaction>) -> bool,
692 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
693 self.pool.pending_transactions_with_predicate(predicate)
694 }
695
696 fn get_pending_transactions_by_sender(
697 &self,
698 sender: Address,
699 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
700 self.pool.get_pending_transactions_by_sender(sender)
701 }
702
703 fn get_queued_transactions_by_sender(
704 &self,
705 sender: Address,
706 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
707 self.pool.get_queued_transactions_by_sender(sender)
708 }
709
710 fn get_highest_transaction_by_sender(
711 &self,
712 sender: Address,
713 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
714 self.pool.get_highest_transaction_by_sender(sender)
715 }
716
717 fn get_highest_consecutive_transaction_by_sender(
718 &self,
719 sender: Address,
720 on_chain_nonce: u64,
721 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
722 self.pool.get_highest_consecutive_transaction_by_sender(sender, on_chain_nonce)
723 }
724
725 fn get_transaction_by_sender_and_nonce(
726 &self,
727 sender: Address,
728 nonce: u64,
729 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
730 let transaction_id = TransactionId::new(self.pool.get_sender_id(sender), nonce);
731
732 self.inner().get_pool_data().all().get(&transaction_id).map(|tx| tx.transaction.clone())
733 }
734
735 fn get_transactions_by_origin(
736 &self,
737 origin: TransactionOrigin,
738 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
739 self.pool.get_transactions_by_origin(origin)
740 }
741
742 /// Returns all pending transactions filtered by [`TransactionOrigin`]
743 fn get_pending_transactions_by_origin(
744 &self,
745 origin: TransactionOrigin,
746 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
747 self.pool.get_pending_transactions_by_origin(origin)
748 }
749
750 fn unique_senders(&self) -> AddressSet {
751 self.pool.unique_senders()
752 }
753
754 fn get_blob(
755 &self,
756 tx_hash: TxHash,
757 ) -> Result<Option<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
758 self.pool.blob_store().get(tx_hash)
759 }
760
761 fn get_all_blobs(
762 &self,
763 tx_hashes: Vec<TxHash>,
764 ) -> Result<Vec<(TxHash, Arc<BlobTransactionSidecarVariant>)>, BlobStoreError> {
765 self.pool.blob_store().get_all(tx_hashes)
766 }
767
768 fn get_all_blobs_exact(
769 &self,
770 tx_hashes: Vec<TxHash>,
771 ) -> Result<Vec<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
772 self.pool.blob_store().get_exact(tx_hashes)
773 }
774
775 fn get_blobs_for_versioned_hashes_v1(
776 &self,
777 versioned_hashes: &[B256],
778 ) -> Result<Vec<Option<BlobAndProofV1>>, BlobStoreError> {
779 self.pool.blob_store().get_by_versioned_hashes_v1(versioned_hashes)
780 }
781
782 fn get_blobs_for_versioned_hashes_v2(
783 &self,
784 versioned_hashes: &[B256],
785 ) -> Result<Option<Vec<BlobAndProofV2>>, BlobStoreError> {
786 self.pool.blob_store().get_by_versioned_hashes_v2(versioned_hashes)
787 }
788
789 fn get_blobs_for_versioned_hashes_v3(
790 &self,
791 versioned_hashes: &[B256],
792 ) -> Result<Vec<Option<BlobAndProofV2>>, BlobStoreError> {
793 self.pool.blob_store().get_by_versioned_hashes_v3(versioned_hashes)
794 }
795}
796
797impl<V, T, S> TransactionPoolExt for Pool<V, T, S>
798where
799 V: TransactionValidator,
800 <V as TransactionValidator>::Transaction: EthPoolTransaction,
801 T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
802 S: BlobStore,
803{
804 type Block = V::Block;
805
806 #[instrument(skip(self), target = "txpool")]
807 fn set_block_info(&self, info: BlockInfo) {
808 trace!(target: "txpool", "updating pool block info");
809 self.pool.set_block_info(info)
810 }
811
812 fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, Self::Block>) {
813 self.pool.on_canonical_state_change(update);
814 }
815
816 fn update_accounts(&self, accounts: Vec<ChangedAccount>) {
817 self.pool.update_accounts(accounts);
818 }
819
820 fn delete_blob(&self, tx: TxHash) {
821 self.pool.delete_blob(tx)
822 }
823
824 fn delete_blobs(&self, txs: Vec<TxHash>) {
825 self.pool.delete_blobs(txs)
826 }
827
828 fn cleanup_blobs(&self) {
829 self.pool.cleanup_blobs()
830 }
831}
832
833impl<V, T: TransactionOrdering, S> Clone for Pool<V, T, S> {
834 fn clone(&self) -> Self {
835 Self { pool: Arc::clone(&self.pool) }
836 }
837}