Transaction Pool
The TxPool manages pending transactions before block inclusion. Tevm's facade is backed by @evmts/zevm/txpool and adds Tevm-specific fee handling for modern fee-market transactions.
Quick Start
import { createTevmNode, PREFUNDED_ACCOUNTS } from 'tevm'
import { createAddress } from 'tevm/address'
import { createImpersonatedTx } from 'tevm/tx'
const node = createTevmNode()
const txPool = await node.getTxPool()
const tx = createImpersonatedTx({
impersonatedAddress: createAddress(PREFUNDED_ACCOUNTS[0].address),
to: createAddress('0x2345678901234567890123456789012345678901'),
value: 1000000000000000000n, // 1 ETH
gasLimit: 21000n,
maxFeePerGas: 20000000000n,
maxPriorityFeePerGas: 20000000000n,
nonce: 0n,
})
await txPool.addUnverified(tx)Key Features
- Transaction Validation — nonce, balance, gas checks
- Transaction Replacement — replace pending tx with higher gas price
- Nonce Ordering — correct sequence per account
- Automatic Pruning — removes stale txs
- Performance Optimized — handles large volumes
- Modern Transaction Support — legacy, EIP-2930, EIP-1559, EIP-4844, EIP-7702, and Tevm impersonated transactions
- JSON-RPC Access —
txpool_content,txpool_contentFrom,txpool_inspect,txpool_status
Core Concepts
Pool Limits
const LIMITS = {
MAX_POOL_SIZE: 5000, // Maximum total transactions
MAX_TXS_PER_ACCOUNT: 100, // Maximum per account
MIN_GAS_PRICE: 100000000n, // 0.1 GWei minimum
TX_MAX_DATA_SIZE: 128 * 1024, // 128KB max transaction size
}Transaction Lifecycle
- Addition — via
add()oraddUnverified() - Validation — optional nonce, balance, gas checks
- Storage — stored and ordered by nonce
- Pruning — removed after
POOLED_STORAGE_TIME_LIMIT(20 minutes)
Detailed Usage
Adding Transactions
// Full validation
try {
await txPool.add(tx)
} catch (error) {
if (error.message.includes('insufficient balance')) {
console.error('Account has insufficient funds')
}
}
// No validation (faster)
await txPool.addUnverified(tx)Transaction Replacement
Submit a new tx with the same nonce and higher gas price (>= 10% bump):
const originalTx = createImpersonatedTx({
// ... base transaction params ...
maxFeePerGas: 20000000000n,
nonce: 0n,
})
const replacementTx = createImpersonatedTx({
// ... same params as original ...
maxFeePerGas: 30000000000n, // At least 10% higher
nonce: 0n,
})
await txPool.addUnverified(originalTx)
await txPool.addUnverified(replacementTx) // Replaces originalTxQuerying Transactions
const senderTxs = await txPool.getBySenderAddress(senderAddress)
const txHashes = [hash1, hash2]
const specificTxs = txPool.getByHash(txHashes)
const orderedTxs = await txPool.txsByPriceAndNonce({
baseFee: currentBaseFee,
allowedBlobs: 6, // For EIP-4844
})Block Processing
import { mineHandler } from 'tevm/actions'
await mineHandler(node)()
txPool.removeNewBlockTxs(newBlocks)Advanced Features
Pool Management
txPool.start() // Start processing
txPool.stop() // Stop (keep transactions)
txPool.close() // Clear all
txPool.cleanup() // Manual cleanup of old txsTransaction Types
Supports: Legacy, EIP-2930 (Access Lists), EIP-1559 (Fee Market), EIP-4844 (Blob), EIP-7702 (EOA Code), and Tevm Impersonated Transactions.
Best Practices
1. Transaction Creation
import { PREFUNDED_ACCOUNTS, parseEther, parseGwei } from 'tevm'
import { createAddress } from 'tevm/address'
import { createImpersonatedTx } from 'tevm/tx'
const tx = createImpersonatedTx({
impersonatedAddress: createAddress(PREFUNDED_ACCOUNTS[0].address),
to: createAddress('0x2345678901234567890123456789012345678901'),
value: parseEther('1'),
gasLimit: 21000n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 0n,
})2. Error Handling
try {
await txPool.add(tx)
} catch (error) {
switch (true) {
case error.message.includes('insufficient balance'):
break
case error.message.includes('nonce too low'):
break
case error.message.includes('gas price too low'):
break
default:
// unknown error
}
}3. Performance Optimization
- Use
addUnverifiedfor bulk operations - Run cleanup cycles
- Monitor pool size and tx age
4. Memory Management
setInterval(() => {
txPool.cleanup()
}, 5 * 60 * 1000) // Every 5 minutes
const poolSize = txPool.txsInPool
if (poolSize > MAX_POOL_SIZE * 0.8) {
console.warn('Pool approaching capacity')
}API Reference
class TxPool {
constructor(options: { vm: Vm })
async add(tx: Transaction): Promise<void>
async addUnverified(tx: Transaction): Promise<void>
async getBySenderAddress(address: Address): Promise<TxPoolObject[]>
getByHash(hashes: Uint8Array[]): Transaction[]
removeByHash(hash: string): void
removeNewBlockTxs(blocks: Block[]): void
start(): boolean
stop(): boolean
cleanup(): void
close(): void
}
