Expand description
Reth’s transaction pool implementation.
This crate provides a generic transaction pool implementation.
§Functionality
The transaction pool is responsible for
- recording incoming transactions
- providing existing transactions
- ordering and providing the best transactions for block production
- monitoring memory footprint and enforce pool size limits
- storing blob data for transactions in a separate blobstore on insertion
§Transaction Flow: From Network/RPC to Pool
Transactions enter the pool through two main paths:
§1. Network Path (P2P)
Network Peer
↓
Transactions or NewPooledTransactionHashes message
↓
TransactionsManager (crates/net/network/src/transactions/mod.rs)
│
├─→ For Transactions message:
│ ├─→ Validates message format
│ ├─→ Checks if transaction already known
│ ├─→ Marks peer as having seen the transaction
│ └─→ Queues for import
│
└─→ For NewPooledTransactionHashes message:
├─→ Filters out already known transactions
├─→ Queues unknown hashes for fetching
├─→ Sends GetPooledTransactions request
├─→ Receives PooledTransactions response
└─→ Queues fetched transactions for import
↓
pool.add_external_transactions() [Origin: External]
↓
Transaction Validation & Pool Addition
§2. RPC Path (Local submission)
eth_sendRawTransaction RPC call
├─→ Decodes raw bytes
└─→ Recovers sender
↓
pool.add_transaction() [Origin: Local]
↓
Transaction Validation & Pool Addition
§Transaction Origins
- Local: Transactions submitted via RPC (trusted, may have different fee requirements)
- External: Transactions from network peers (untrusted, subject to stricter validation)
- Private: Local transactions that should not be propagated to the network
§Validation Process
§Stateless Checks
Ethereum transactions undergo several stateless checks:
- Transaction Type: Fork-dependent support (Legacy always, EIP-2930/1559/4844/7702 need activation)
- Size: Input data ≤ 128KB (default)
- Gas: Limit ≤ block gas limit
- Fees: Priority fee ≤ max fee; local tx fee cap; external minimum priority fee
- Chain ID: Must match current chain
- Intrinsic Gas: Sufficient for data and access lists
- Blobs (EIP-4844): Valid count, KZG proofs
§Stateful Checks
- Sender: No bytecode (unless EIP-7702 delegated in Prague)
- Nonce: ≥ account nonce
- Balance: Covers value + (
gas_limit
×max_fee_per_gas
)
§Common Errors
NonceNotConsistent
: Nonce too lowInsufficientFunds
: Insufficient balanceExceedsGasLimit
: Gas limit too highSignerAccountHasBytecode
: EOA has codeUnderpriced
: Fee too lowReplacementUnderpriced
: Replacement transaction fee too low- Blob errors:
MissingEip4844BlobSidecar
: Missing sidecarInvalidEip4844Blob
: Invalid blob proofsNoEip4844Blobs
: EIP-4844 transaction without blobsTooManyEip4844Blobs
: Too many blobs
§Subpool Design
The pool maintains four distinct subpools, each serving a specific purpose
§Subpools
- Pending: Ready for inclusion (no gaps, sufficient balance/fees)
- Queued: Future transactions (nonce gaps or insufficient balance)
BaseFee
: Valid but below current base fee- Blob: EIP-4844 transactions not pending due to insufficient base fee or blob fee
§State Transitions
Transactions move between subpools based on state changes:
Queued ─────────→ BaseFee/Blob ────────→ Pending
↑ ↑ │
│ │ │
└────────────────────┴─────────────────────┘
(demotions due to state changes)
Promotions: Nonce gaps filled, balance/fee improvements Demotions: Nonce gaps created, balance/fee degradation
§Pool Maintenance
- Block Updates: Removes mined txs, updates accounts/fees, triggers movements
- Size Enforcement: Discards worst transactions when limits exceeded
- Propagation: External (always), Local (configurable), Private (never)
§Assumptions
§Transaction type
The pool expects certain ethereum related information from the generic transaction type of the
pool (PoolTransaction
), this includes gas price, base fee (EIP-1559 transactions), nonce
etc. It makes no assumptions about the encoding format, but the transaction type must report its
size so pool size limits (memory) can be enforced.
§Transaction ordering
The pending pool contains transactions that can be mined on the current state.
The order in which they’re returned are determined by a Priority
value returned by the
TransactionOrdering
type this pool is configured with.
This is only used in the pending pool to yield the best transactions for block production. The base pool is ordered by base fee, and the queued pool by current distance.
§Validation
The pool itself does not validate incoming transactions, instead this should be provided by
implementing TransactionsValidator
. Only transactions that the validator returns as valid are
included in the pool. It is assumed that transaction that are in the pool are either valid on
the current state or could become valid after certain state changes. Transactions that can never
become valid (e.g. nonce lower than current on chain nonce) will never be added to the pool and
instead are discarded right away.
§State Changes
New blocks trigger pool updates via changesets (see Pool Maintenance).
§Implementation details
The TransactionPool
trait exposes all externally used functionality of the pool, such as
inserting, querying specific transactions by hash or retrieving the best transactions.
In addition, it enables the registration of event listeners that are notified of state changes.
Events are communicated via channels.
§Architecture
The final TransactionPool
is made up of two layers:
The lowest layer is the actual pool implementations that manages (validated) transactions:
TxPool
. This is contained in a higher level pool type that
guards the low level pool and handles additional listeners or metrics: PoolInner
.
The transaction pool will be used by separate consumers (RPC, P2P), to make sharing easier, the
Pool
type is just an Arc
wrapper around PoolInner
. This is the usable type that provides
the TransactionPool
interface.
§Blob Transactions
Blob transaction can be quite large hence they are stored in a separate blobstore. The pool is
responsible for inserting blob data for new transactions into the blobstore.
See also ValidTransaction
§Examples
Listen for new transactions and print them:
use reth_chainspec::MAINNET;
use reth_storage_api::StateProviderFactory;
use reth_tasks::TokioTaskExecutor;
use reth_chainspec::ChainSpecProvider;
use reth_transaction_pool::{TransactionValidationTaskExecutor, Pool, TransactionPool};
use reth_transaction_pool::blobstore::InMemoryBlobStore;
use reth_chainspec::EthereumHardforks;
async fn t<C>(client: C) where C: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory + Clone + 'static{
let blob_store = InMemoryBlobStore::default();
let pool = Pool::eth_pool(
TransactionValidationTaskExecutor::eth(client, blob_store.clone(), TokioTaskExecutor::default()),
blob_store,
Default::default(),
);
let mut transactions = pool.pending_transactions_listener();
tokio::task::spawn( async move {
while let Some(tx) = transactions.recv().await {
println!("New transaction: {:?}", tx);
}
});
// do something useful with the pool, like RPC integration
Spawn maintenance task to keep the pool updated
use futures_util::Stream;
use reth_chain_state::CanonStateNotification;
use reth_chainspec::{MAINNET, ChainSpecProvider, ChainSpec};
use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
use reth_tasks::TokioTaskExecutor;
use reth_tasks::TaskSpawner;
use reth_tasks::TaskManager;
use reth_transaction_pool::{TransactionValidationTaskExecutor, Pool};
use reth_transaction_pool::blobstore::InMemoryBlobStore;
use reth_transaction_pool::maintain::{maintain_transaction_pool_future};
use alloy_consensus::Header;
async fn t<C, St>(client: C, stream: St)
where C: StateProviderFactory + BlockReaderIdExt<Header = Header> + ChainSpecProvider<ChainSpec = ChainSpec> + Clone + 'static,
St: Stream<Item = CanonStateNotification> + Send + Unpin + 'static,
{
let blob_store = InMemoryBlobStore::default();
let rt = tokio::runtime::Runtime::new().unwrap();
let manager = TaskManager::new(rt.handle().clone());
let executor = manager.executor();
let pool = Pool::eth_pool(
TransactionValidationTaskExecutor::eth(client.clone(), blob_store.clone(), executor.clone()),
blob_store,
Default::default(),
);
// spawn a task that listens for new blocks and updates the pool's transactions, mined transactions etc..
tokio::task::spawn(maintain_transaction_pool_future(client, pool, stream, executor.clone(), Default::default()));
§Feature Flags
serde
(default): Enable serde supporttest-utils
: Export utilities for testing
Re-exports§
pub use crate::blobstore::BlobStore;
pub use crate::blobstore::BlobStoreError;
pub use crate::error::PoolResult;
pub use crate::pool::blob_tx_priority;
pub use crate::pool::fee_delta;
pub use crate::pool::AllTransactionsEvents;
pub use crate::pool::FullTransactionEvent;
pub use crate::pool::NewTransactionEvent;
pub use crate::pool::TransactionEvent;
pub use crate::pool::TransactionEvents;
pub use crate::pool::TransactionListenerKind;
pub use crate::validate::EthTransactionValidator;
pub use crate::validate::TransactionValidationOutcome;
pub use crate::validate::TransactionValidationTaskExecutor;
pub use crate::validate::TransactionValidator;
pub use crate::validate::ValidPoolTransaction;
Modules§
- blobstore
- Storage for blob data of EIP4844 transactions.
- error
- Transaction pool errors
- identifier
- Identifier types for transactions and senders.
- maintain
- Support for maintaining the state of the transaction pool
- metrics
- Transaction pool metrics.
- noop
- A transaction pool implementation that does nothing.
- pool
- Transaction Pool internals.
- test_
utils test-utils
- Common test helpers for mocking a pool Internal helpers for testing.
- validate
- Transaction validation abstractions.
Structs§
- AllPool
Transactions - A Helper type that bundles all transactions in the pool.
- Best
Transactions Attributes - A Helper type that bundles the best transactions attributes together.
- Block
Info - Represents the current status of the pool.
- Canonical
State Update - Represents changes after a new canonical block or range of canonical blocks was added to the chain.
- Coinbase
TipOrdering - Default ordering for the pool.
- EthPooled
Transaction - The default
PoolTransaction
for the Pool for Ethereum. - Local
Transaction Config - Configuration options for the locally received transactions:
TransactionOrigin::Local
- NewBlob
Sidecar - This type represents a new blob sidecar that has been stored in the transaction pool’s
blobstore; it includes the
TransactionHash
of the blob transaction along with the assoc. sidecar (blobs, commitments, proofs) - NewSubpool
Transaction Stream - A Stream that yields full transactions the subpool
- Noop
Transaction Filter - A no-op implementation of
TransactionFilter
which marks all transactions as valid. - Pool
- A shareable, generic, customizable
TransactionPool
implementation. - Pool
Config - Configuration options for the Transaction pool.
- Pool
Size - Represents the current status of the pool.
- Price
Bump Config - Price bump config (in %) for the transaction pool underpriced check.
- Propagated
Transactions - Represents transactions that were propagated over the network.
- SubPool
Limit - Size limits for a sub-pool.
Enums§
- EthBlob
Transaction Sidecar - Represents the blob sidecar of the
EthPooledTransaction
. - GetPooled
Transaction Limit - The limit to enforce for
TransactionPool::get_pooled_transaction_elements
. - Pool
Update Kind - Represents the kind of update to the canonical state.
- Priority
- Priority of the transaction that can be missing.
- Propagate
Kind - Represents how a transaction was propagated over the network.
- SubPool
- Identifier for the transaction Sub-pool
- Transaction
Origin - Where the transaction originates from.
Constants§
- DEFAULT_
PRICE_ BUMP - Default price bump (in %) for the transaction pool underpriced check.
- DEFAULT_
TXPOOL_ ADDITIONAL_ VALIDATION_ TASKS - The default additional validation tasks size.
- MAX_
NEW_ PENDING_ TXS_ NOTIFICATIONS - Default maximum new transactions for broadcasting.
- REPLACE_
BLOB_ PRICE_ BUMP - Replace blob price bump (in %) for the transaction pool underpriced check.
- TXPOOL_
MAX_ ACCOUNT_ SLOTS_ PER_ SENDER - Guarantees max transactions for one sender, compatible with geth/erigon
- TXPOOL_
SUBPOOL_ MAX_ SIZE_ MB_ DEFAULT - The default maximum allowed size of the given subpool.
- TXPOOL_
SUBPOOL_ MAX_ TXS_ DEFAULT - The default maximum allowed number of transactions in the given subpool.
Traits§
- Best
Transactions - An
Iterator
that only returns transactions that are ready to be executed. - EthPool
Transaction - Super trait for transactions that can be converted to and from Eth transactions intended for the ethereum style pool.
- Pool
Transaction - Trait for transaction types stored in the transaction pool.
- Transaction
Filter - A filter that allows to check if a transaction satisfies a set of conditions
- Transaction
Ordering - Transaction ordering trait to determine the order of transactions.
- Transaction
Pool - General purpose abstraction of a transaction-pool.
- Transaction
Pool Ext - Extension for
TransactionPool
trait that allows to set the current block info.
Type Aliases§
- Best
Transactions For - Alias to restrict the
BestTransactions
items to the pool’s transaction type. - EthTransaction
Pool - Type alias for default ethereum transaction pool
- PeerId
- The
PeerId
type. - Pool
Consensus Tx - Helper type alias to access
PoolTransaction::Consensus
for a givenTransactionPool
. - Pool
Pooled Tx - Helper type alias to access
PoolTransaction::Pooled
for a givenTransactionPool
. - PoolTx
- Helper type alias to access
PoolTransaction
for a givenTransactionPool
.