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