Transaction Pool
The Transaction Pool (TxPool) is a crucial component that manages pending transactions before they're included in blocks. It handles transaction ordering, replacement, validation, and lifecycle management.
Quick Start
import { createTevmNode } from 'tevm'
import { createAddress } from 'tevm/address'
import { createImpersonatedTx } from 'tevm/tx'
// Initialize node and get txpool
const node = createTevmNode()
const txPool = await node.getTxPool()
// Create and add a transaction
const tx = createImpersonatedTx({
impersonatedAddress: createAddress('0x1234...'),
to: createAddress('0x2345...'),
value: 1000000000000000000n, // 1 ETH
gasLimit: 21000n,
maxFeePerGas: 20000000000n,
maxPriorityFeePerGas: 20000000000n,
nonce: 0n,
})
await txPool.addUnverified(tx)
Key Features
- ๐ Transaction Validation - Comprehensive validation including nonce, balance, and gas checks
- ๐ Transaction Replacement - Replace pending transactions with higher gas price versions
- ๐ Nonce Ordering - Maintains correct transaction sequence per account
- ๐งน Automatic Pruning - Removes old transactions to prevent memory bloat
- โก Performance Optimized - Efficient handling of large transaction volumes
Core Concepts
Pool Limits
The TxPool enforces several limits to ensure stable operation:
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 - Transactions enter the pool via
add()
oraddUnverified()
- Validation - Optional checks for nonce, balance, and gas parameters
- Storage - Valid transactions are stored and ordered by nonce
- Pruning - Old transactions are removed after
POOLED_STORAGE_TIME_LIMIT
(20 minutes)
Detailed Usage
Adding Transactions
Two methods for adding transactions, each with different validation levels:
// Method 1: With full validation
try {
await txPool.add(tx)
} catch (error) {
if (error.message.includes('insufficient balance')) {
console.error('Account has insufficient funds')
}
}
// Method 2: Without validation (faster)
await txPool.addUnverified(tx)
Transaction Replacement
Replace a pending transaction by submitting a new one with the same nonce and higher gas price:
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, // Same nonce as original
})
await txPool.addUnverified(originalTx)
await txPool.addUnverified(replacementTx) // Replaces originalTx
Note: Replacement transactions must increase gas price by at least
MIN_GAS_PRICE_BUMP_PERCENT
(10%)
Querying Transactions
// Get transactions by sender
const senderTxs = await txPool.getBySenderAddress(senderAddress)
// Get transactions by hash
const txHashes = [hash1, hash2]
const specificTxs = txPool.getByHash(txHashes)
// Get ordered transactions for mining
const orderedTxs = await txPool.txsByPriceAndNonce({
baseFee: currentBaseFee,
allowedBlobs: 6, // For EIP-4844
})
Block Processing
When new blocks are added, update the pool:
import { mineHandler } from 'tevm/actions'
// Mine new blocks
await mineHandler(node)()
// Remove included transactions
txPool.removeNewBlockTxs(newBlocks)
Advanced Features
Pool Management
// Start transaction processing
txPool.start()
// Stop processing (but keep transactions)
txPool.stop()
// Clear all transactions
txPool.close()
// Manual cleanup of old transactions
txPool.cleanup()
Transaction Types
The pool supports all Ethereum transaction types:
- Legacy Transactions
- EIP-2930 (Access Lists)
- EIP-1559 (Fee Market)
- EIP-4844 (Blob Transactions)
- Tevm Impersonated Transactions
Best Practices
1. Transaction Creation
Always use createImpersonatedTx
with proper types:
const tx = createImpersonatedTx({
impersonatedAddress: createAddress(address),
to: createAddress(recipient),
value: parseEther('1'), // Use helper functions for values
gasLimit: 21000n,
maxFeePerGas: gweiToWei('20'),
maxPriorityFeePerGas: gweiToWei('2'),
nonce: 0n,
})
2. Error Handling
Implement comprehensive error handling:
try {
await txPool.add(tx)
} catch (error) {
switch (true) {
case error.message.includes('insufficient balance'):
// Handle balance error
break
case error.message.includes('nonce too low'):
// Handle nonce error
break
case error.message.includes('gas price too low'):
// Handle gas price error
break
default:
// Handle unknown errors
}
}
3. Performance Optimization
- Use
addUnverified
for bulk operations - Implement proper cleanup cycles
- Monitor pool size and transaction age
4. Memory Management
// Regular cleanup cycle
setInterval(() => {
txPool.cleanup()
}, 5 * 60 * 1000) // Every 5 minutes
// Monitor pool size
const poolSize = txPool.txsInPool
if (poolSize > MAX_POOL_SIZE * 0.8) {
console.warn('Pool approaching capacity')
}
API Reference
TxPool Class
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
}