Fuzz the Ethereum networking stack—end to end.
D2PFuzz generates and mutates DevP2P traffic (discv4/5, RLPx, eth/*
) and drives tx-level fuzzing to surface client-specific mempool, networking, and consensus-edge bugs across Geth, Nethermind, Erigon, Besu, Reth, etc.
- Protocol fuzzing: craft/sequence valid & mutated packets for discv4, discv5, RLPx, and
eth
sub-protocols. - Transaction fuzzing: sustained, patterned load with optional mutation and multi-RPC load balancing.
- Reproducible: deterministic seeds and captured outputs for one-tx counterexamples.
- Operable: simple YAML config, scripts to spin up a local multi-client devnet, real-time stats and JSON reports.
D2PFuzz/
├── account/ # Account management
├── blob/ # Blob transaction component
├── cmd/ # Command-line tools directory
│ ├── livefuzzer/ # Transaction fuzzer tool
│ └── manual/ # Manual testing tool
├── config/ # Configuration modules
├── devp2p/ # P2P network protocol modules
├── ethclient/ # Unified client management
├── fuzzer/ # Fuzzing core modules
├── logs/ # Log files directory
├── mutation/ # Mutation strategies
├── output/ # Reports storage directory
├── poc/ # Proof of Concept implementations
├── rpc/ # Local rpc component
├── scripts/ # Helper scripts
├── stress_test/ # Stress testing directory
├── templates/ # Template config files
├── testing/ # Test runner framework
├── transaction/ # Transaction building
├── utils/ # Utility functions
├── config.yaml # Main configuration file
├── constants.go # Global constants
├── main.go # Program entry point
└── README.md # Usage of the repository
- Go 1.21+
- Docker & Docker Compose (for local multi-client testnet)
- Git
git clone https://github.com/AgnopraxLab/D2PFuzz.git
cd D2PFuzz
go mod tidy
We use ethpandaops/ethereum-package
.
./scripts/run_ethereum_network.sh -c <your_ethereumpackage_config.yaml>
# Produces scripts/output.txt with enodes and RPC URLs
Grab enodes/RPCs from scripts/output.txt
and fill your YAML (see templates/
).
A command-line tool for testing Ethereum P2P nodes.
- Single node testing - Test specific nodes independently
- Multi-node testing - Test all configured nodes simultaneously
- Soft limit testing - Validate NewPooledTransactionHashes soft limit implementation
- GetPooledTransactions testing - Test transaction pool queries
1. Build the tool:
cd cmd/manual
go build -o manual
2. Configure (edit cmd/manual/config.yaml
):
test:
mode: "single" # Test mode
single_node_index: 4 # Which node to test (0-4)
single_node_batch_size: 1 # Number of transactions
3. Run tests:
# Use default config
./manual
# Specify custom config
./manual -config /path/to/config.yaml
# Override test mode from command line
./manual -mode multi
# List all available test modes
./manual --list
# Show version
./manual --version
Mode | Description |
---|---|
single |
Test a single specific node |
multi |
Test all configured nodes |
test-soft-limit |
Test soft limit for all clients |
test-soft-limit-single |
Test soft limit for one client |
test-soft-limit-report |
Generate soft limit test report |
GetPooledTxs |
Test GetPooledTransactions protocol |
oneTransaction |
Send a single transaction |
largeTransactions |
Send large batch of transactions |
The manual tool uses its own config.yaml
in cmd/manual/
directory, independent from the root project configuration:
# P2P Configuration
p2p:
jwt_secret: "..."
node_names:
- "geth-lighthouse"
- "netherhmind-teku"
- "besu-prysm"
- "besu-lodestar"
- "geth-nimbus"
bootstrap_nodes: [...]
# Test Configuration
test:
mode: "single"
single_node_index: 4
single_node_nonce: 1
single_node_batch_size: 1
multi_node_batch_size: 20
multi_node_nonces: [0, 0, 0, 0, 0]
soft_limit_scenarios: [4096, 5000, 8192]
Single Node Test:
cd cmd/manual
./manual -mode single
# Tests node 4 (configured in config.yaml) with 1 transaction
Multi-Node Test:
./manual -mode multi
# Tests all 5 configured nodes with 20 transactions each
Soft Limit Testing:
./manual -mode test-soft-limit-report
# Generates comprehensive soft limit test report for all clients
Custom Configuration:
./manual -config my-test-config.yaml -mode single
# Use custom config file
cd stress_test
./run_stress_test.sh
Specialized testing tools for specific scenarios.
Test extreme nonce values (math.MaxUint64
) to verify how Ethereum clients handle boundary conditions.
Quick Start:
cd poc/maxNonce
# Edit maxNonce.go to configure your node parameters
go run maxNonce.go
Expected Result: Transaction should be QUEUED
(waiting for conditions) due to extreme nonce value.
cd cmd
./livefuzzer spam --seed <seed> --sk <hex_private_key> -rpc <rpc_url>
--seed
any int (use fixed for reproducibility)--sk
account private key (fund it on your devnet)-rpc
target RPC (repeat flag to load balance across many)
More flags mirror tx-fuzz.
tx_fuzz:
enabled: true
chain_id: 3151908
tx_per_second: 10
fuzz_duration_sec: 60
seed: 0 # 0 = random
use_accounts: true
# gas
max_gas_price: 20000000000 # 20 gwei
max_gas_limit: 8000000
# multi-node
rpc_endpoints:
- "http://172.16.0.11:8545"
- "http://172.16.0.12:8545"
# retries
max_retries: 3
retry_delay: 1s
circuit_breaker: true
failure_threshold: 5
# load shape: constant | ramp | spike | wave
load_pattern_type: "ramp"
fuzzConfig := &fuzzer.TxFuzzConfig{
UseMutation: true,
MutationRatio: 0.3, // 30% mutated
EnableTracking: true, // track mined/failed/pending
ConfirmBlocks: 3,
}
EnableMetrics: true
MetricsInterval: 10 * time.Second
-
TPS (
tx_per_second
)- Devnet sanity: 5–20
- Stress: 50–100
- Extreme: 100+
-
Duration (
fuzz_duration_sec
)- Quick: 30–60s
- Standard: 300–600s
- Long: ≥3600s
-
Load shape
constant
: stabilityramp
: progressive stress (recommended)spike
: peak/burstwave
: long-run stability
Tips: ramp up gradually, monitor latency/success, distribute load across multiple RPCs.
Generated under output/
:
tx_fuzz_results.json
— per-tx records, timing, outcomes, mutation flagssuccess_tx_hashes.txt
— mined tx hashesfailed_tx_hashes.txt
— failures for triage
Real-time console sample:
--- Stats (Runtime: 30s) ---
Total Sent: 150 | Mined: 145 | Failed: 3 | Pending: 2
Mutation Used: 45 | Random Used: 105
Success Rate: 96.7% | Mutation Rate: 30.0%
-
connection refused
- Confirm RPC is reachable; node is up; firewall rules allow access.
-
insufficient funds for gas
- Fund the sender; lower
max_gas_price
/max_gas_limit
.
- Fund the sender; lower
-
Low observed TPS
- Check network latency; reduce
max_retries
/retry_delay
; add RPCs and increase concurrency.
- Check network latency; reduce
-
High memory
- Shorten
fuzz_duration_sec
; disable tracking; lower TPS.
- Shorten
Lightweight
tx_fuzz:
tx_per_second: 5
fuzz_duration_sec: 30
max_gas_price: 10000000000
load_pattern_type: "constant"
Stress
tx_fuzz:
tx_per_second: 50
fuzz_duration_sec: 300
max_gas_price: 50000000000
load_pattern_type: "ramp"
Extreme
tx_fuzz:
tx_per_second: 100
fuzz_duration_sec: 600
max_gas_price: 100000000000
load_pattern_type: "spike"
- Protocol fuzzing targets discv4/5 discovery, RLPx handshakes/frames, and
eth/*
messages (Ping/Pong/NewBlock/Txs, etc.), including mutated sequences and time/chain-state-aware flows. - Tx-fuzz complements network fuzzing by stressing mempool rules (nonce gaps, gas pricing, batch shapes) and surfacing divergent behaviors across clients.
MIT. See LICENSE.
Current: v0.3
Older, fully tested snapshots: archive-v0.1
, archive-v0.2
.