| name | local-mainnet-debug |
| description | Debug Lodestar beacon node issues by running a local mainnet node with checkpoint sync and engineMock. Use for investigating networking bugs, peer discovery issues, identify failures, metrics anomalies, or any behavior that needs real-world peer interactions without a full execution client. |
Local Mainnet Debugging
Run a local Lodestar beacon node against mainnet peers using checkpoint sync and engineMock to reproduce and debug networking, peer discovery, and protocol-level issues in a real-world environment.
Quick Start
cd ~/lodestar
./lodestar beacon \
--network mainnet \
--rest false \
--metrics \
--execution.engineMock \
--port 19771 \
--logLevel debug \
--checkpointSyncUrl https://beaconstate-mainnet.chainsafe.io \
--forceCheckpointSync
timeout 120 ./lodestar beacon \
--network mainnet \
--rest false \
--metrics \
--execution.engineMock \
--port 19771 \
--logLevel debug \
--checkpointSyncUrl https://beaconstate-mainnet.chainsafe.io \
--forceCheckpointSync
Key Parameters
| Parameter | Purpose | Notes |
|---|
--network mainnet | Connect to real mainnet peers | Use holesky for testnet |
--execution.engineMock | Skip EL requirement | Node won't validate execution payloads |
--rest false | Disable REST API | Reduces noise, avoids port conflicts |
--metrics | Enable Prometheus metrics | Scrape at http://localhost:8008/metrics |
--port 19771 | Custom P2P port | Avoid conflicts with other instances |
--logLevel debug | Verbose logging | Use trace for maximum detail |
--checkpointSyncUrl | Checkpoint sync endpoint | https://beaconstate-mainnet.chainsafe.io for mainnet |
--forceCheckpointSync | Force checkpoint sync even if DB exists | Clean start each run |
Catch-Up Repro Depth Guard
For sync-depth or OOM repros, validate the checkpoint is far enough behind head before launching the node. A latest-finalized checkpoint is usually too shallow for catch-up backlog investigations.
~/.openclaw/workspace/scripts/debug/check-catchup-depth.sh \
--head-slot 14415648 \
--checkpoint-slot 14383648 \
--min-epochs 1000
~/.openclaw/workspace/scripts/debug/check-catchup-depth.sh \
--beacon-url http://127.0.0.1:5052 \
--checkpoint-sync-url https://beaconstate-mainnet.chainsafe.io \
--min-epochs 1000
Exit 2 means the checkpoint is too shallow or ahead of head; find an older /eth/v2/debug/beacon/states/<slot> state and use --checkpointState instead of starting the repro.
Metrics Scraping
curl -s http://localhost:8008/metrics | grep <pattern>
while true; do
echo "=== $(date -u +%H:%M:%S) ==="
curl -s http://localhost:8008/metrics | grep -E 'lodestar_peers_by_client|peer_count'
sleep 30
done
curl -s http://localhost:8008/metrics | grep -E \
'lodestar_peers_by_client|libp2p_identify|peer_count|connected_peers'
Incident Bundle Preflight
Before starting a longer incident bundle or devnet triage run, validate that the helper scripts, output path, and telemetry prerequisites are usable. Use --require-grafana when a partial bundle without Grafana logs/metrics would not answer the question.
~/.openclaw/workspace/scripts/debug/build-incident-bundle.sh \
--node lodestar-b2 \
--peer lighthouse-b2 \
--window 1h \
--require-grafana \
--check-only
Exit non-zero means fix the missing token/tooling/output path before collecting data. Omit --require-grafana only when a local/process-only bundle is intentionally sufficient.
Debugging Techniques
1. Instrument libp2p Internals (Monkeypatching)
For deep protocol debugging, add temporary instrumentation to node_modules:
find node_modules -path '*libp2p*identify*' -name '*.js' | head -20
Important: Always remove monkeypatches before committing or running validation. Use git checkout node_modules/ or pnpm install to restore.
2. A/B Testing with Code Changes
When testing a hypothesis:
- Control run: Baseline with current code, capture metrics
- Test run: Apply change, capture metrics
- Compare: Same duration, same metric sampling
timeout 120 ./lodestar beacon [flags] 2>&1 | tee /tmp/control.log &
for i in $(seq 1 4); do sleep 30; curl -s http://localhost:8008/metrics > /tmp/control-$i.metrics; done
timeout 120 ./lodestar beacon [flags] 2>&1 | tee /tmp/test.log &
for i in $(seq 1 4); do sleep 30; curl -s http://localhost:8008/metrics > /tmp/test-$i.metrics; done
diff <(grep pattern /tmp/control-4.metrics) <(grep pattern /tmp/test-4.metrics)
3. Log Analysis
grep -c "Error setting agentVersion" /tmp/run.log
grep -E "identify (success|error|timeout)" /tmp/run.log | head -50
grep -E "peer:(connect|disconnect|identify)" /tmp/run.log
4. Stream-Level Debugging
For protocol stream issues (identify, ping, metadata):
Common Issues & Root Causes
Unknown Peers (identify failures)
Symptoms: High ratio of "Unknown" in lodestar_peers_by_client metric.
Root cause found (2026-02-25): @libp2p/prometheus-metrics trackProtocolStream() attaches a message event listener that races with identify's pb.read() for the first data frame. The metrics listener can consume the identify response before the identify handler reads it.
Fix: Skip trackProtocolStream for /ipfs/id/1.0.0 protocol. See PR #8958.
Upstream fix: libp2p/js-libp2p#3378 — byteStream should check its own readBuffer before returning null.
Diagnostic approach:
- Check
lodestar_peers_by_client for Unknown ratio
- Enable debug logs, grep for "Error setting agentVersion"
- Instrument identify stream to check
remoteWriteStatus before pb.read()
- A/B test: disable
trackProtocolStream entirely → if Unknown drops to 0, it's the metrics race
Checkpoint Sync Failures
--checkpointSyncUrl https://beaconstate-mainnet.chainsafe.io
--checkpointSyncUrl https://mainnet-checkpoint-sync.stakely.io
--checkpointSyncUrl https://sync-mainnet.beaconcha.in
Port Conflicts
lsof -i :19771
lsof -i :8008
--port 19772 --metrics.port 8009
Cleanup
rm -rf ~/.local/share/lodestar/mainnet
--dataDir /tmp/lodestar-debug
Tips
- Short runs are fine. 60-120 seconds is enough to connect to 15-30 peers and observe identify behavior.
- engineMock means no execution validation. The node will sync headers but won't validate blocks. This is fine for networking/peer debugging.
- Custom port avoids conflicts with any production nodes on the same machine.
- Always use
--forceCheckpointSync to ensure a clean start. Stale DB state can mask issues.
- Metrics lag behind logs. After stopping the node, the last metrics scrape reflects final state. Periodic sampling during the run gives time-series data.
- Debug builds not needed. The standard
pnpm build output is sufficient; libp2p debug info comes from log level and instrumentation.
Self-Maintenance
If any commands, file paths, URLs, or configurations in this skill are outdated or no longer work, update this SKILL.md with the correct information after completing your current task. Skills should stay accurate and self-healing — fix what you find broken.