Launch erigon + Lighthouse on the bal-devnet-2 ethpandaops devnet (EIP-7928 Block Access Lists). Manages start/stop of both EL and CL clients with proper port offsets and JWT auth.
Run erigon (EL) + Lighthouse (CL) on the bal-devnet-2 ethpandaops devnet for testing EIP-7928 Block Access Lists.
| Parameter | Value |
|---|---|
| Chain ID | 7033429093 |
| Genesis timestamp | 1770388190 |
| Amsterdam timestamp | 1770400508 (epoch 32) |
| Lighthouse image | ethpandaops/lighthouse:bal-devnet-2-65bb283 |
| Lighthouse version | v8.0.1 (commit 65bb283, branch bal-devnet-2) |
| Explorer | https://explorer.bal-devnet-2.ethpandaops.io |
| Faucet | https://faucet.bal-devnet-2.ethpandaops.io |
| RPC | https://rpc.bal-devnet-2.ethpandaops.io |
| Checkpoint sync | https://checkpoint-sync.bal-devnet-2.ethpandaops.io |
Ask the user where they want the working directory. Default suggestion: ~/bal-devnet-2/.
Use $WORKDIR throughout to refer to the chosen path.
$WORKDIR/
├── genesis.json # EL genesis
├── config.yaml # CL beacon config
├── genesis.ssz # CL genesis state
├── testnet-config/ # Lighthouse testnet dir (config.yaml + genesis.ssz + deploy files)
├── start-erigon.sh # Erigon start script (run FIRST)
├── start-lighthouse.sh # Lighthouse start script (run SECOND)
├── stop.sh # Stop both erigon + Lighthouse
├── clean.sh # Stop, wipe data, re-init genesis
├── erigon-data/ # Erigon datadir (contains jwt.hex)
├── lighthouse-data/ # Lighthouse datadir
├── erigon-console.log # Erigon stdout/stderr
└── lighthouse-console.log # Lighthouse stdout/stderr
| Service | Port | Protocol |
|---|---|---|
| Erigon HTTP RPC | 8645 | TCP |
| Erigon Engine API (authrpc) | 8651 | TCP |
| Erigon WebSocket | 8646 | TCP |
| Erigon P2P | 30403 | TCP+UDP |
| Erigon gRPC | 9190 | TCP |
| Erigon Torrent | 42169 | TCP+UDP |
| Erigon pprof | 6160 | TCP |
| Erigon metrics | 6161 | TCP |
| Lighthouse P2P | 9100 | TCP+UDP |
| Lighthouse QUIC | 9101 | UDP |
| Lighthouse HTTP API | 5152 | TCP |
| Lighthouse metrics | 5264 | TCP |
./build/bin/erigon. If not, invoke /erigon-build.docker image inspect ethpandaops/lighthouse:bal-devnet-2-65bb283 > /dev/null 2>&1
If not, pull it:
docker pull ethpandaops/lighthouse:bal-devnet-2-65bb283
$WORKDIR (genesis.json, testnet-config/).
If not, download them:
mkdir -p $WORKDIR/testnet-config
curl -sL -o $WORKDIR/genesis.json https://config.bal-devnet-2.ethpandaops.io/el/genesis.json
curl -sL -o $WORKDIR/testnet-config/config.yaml https://config.bal-devnet-2.ethpandaops.io/cl/config.yaml
curl -sL -o $WORKDIR/testnet-config/genesis.ssz https://config.bal-devnet-2.ethpandaops.io/cl/genesis.ssz
echo "0" > $WORKDIR/testnet-config/deposit_contract_block.txt
echo "0" > $WORKDIR/testnet-config/deploy_block.txt
If $WORKDIR/erigon-data/chaindata does not exist:
./build/bin/erigon init --datadir $WORKDIR/erigon-data $WORKDIR/genesis.json
If the start/stop/clean scripts don't exist yet, generate them. The scripts must use absolute paths based on $WORKDIR. Key details:
start-erigon.sh — Runs erigon with --externalcl. Must start FIRST (creates JWT secret).
ERIGON_EXEC3_PARALLEL=true, ERIGON_ASSERT=true, ERIGON_EXEC3_WORKERS=12, LOG_HASH_MISMATCH_REASON=true--datadir=$WORKDIR/erigon-data, --externalcl, --networkid=7033429093, all 16 EL bootnodes, erigon static peers, --prune.mode=minimal, all offset ports (see port table), --http.api=eth,erigon,engine,debug, --pprof, --metricshttps://config.bal-devnet-2.ethpandaops.io/api/v1/nodes/inventory (extract enode URLs from execution.enode fields)start-lighthouse.sh — Runs Lighthouse via Docker with --network=host. Must start SECOND.
$WORKDIR/erigon-data/jwt.hexbal-devnet-2-lighthouse$WORKDIR/testnet-config:/config:ro, $WORKDIR/lighthouse-data:/data, JWT as /jwt.hex:ro--testnet-dir=/config, --execution-endpoint=http://127.0.0.1:8651, --execution-jwt=/jwt.hex, all 15 CL ENR bootnodes, offset ports, --checkpoint-sync-url=https://checkpoint-sync.bal-devnet-2.ethpandaops.ioconsensus.enr fields)stop.sh — Stops Lighthouse (docker stop bal-devnet-2-lighthouse) then erigon (pkill -f "datadir.*bal-devnet-2/erigon-data").
clean.sh — Runs stop.sh, removes erigon chain data (chaindata, snapshots, txpool, nodes, temp) and lighthouse data, re-initializes genesis.
Erigon must start first because it creates the JWT secret that Lighthouse needs.
cd $WORKDIR && nohup bash start-erigon.sh > erigon-console.log 2>&1 &
Verify it started:
tail $WORKDIR/erigon-console.log for startup messagesls $WORKDIR/erigon-data/jwt.hexss -tlnp | grep 8651After erigon is running and JWT exists:
cd $WORKDIR && nohup bash start-lighthouse.sh > lighthouse-console.log 2>&1 &
Verify it started:
tail $WORKDIR/lighthouse-console.log for "Lighthouse started"peers: "N" showing peer connections# Erigon sync progress
tail -f $WORKDIR/erigon-console.log
# Lighthouse sync progress
tail -f $WORKDIR/lighthouse-console.log
# Check erigon block height via RPC
curl -s http://localhost:8645 -X POST -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | python3 -m json.tool
# Check lighthouse sync status
curl -s http://localhost:5152/eth/v1/node/syncing | python3 -m json.tool
bash $WORKDIR/stop.sh
This stops Lighthouse (via docker stop) then erigon (via pkill).
bash $WORKDIR/clean.sh
This runs stop.sh, removes erigon chain data (chaindata, snapshots, txpool, nodes, temp) and lighthouse data, then re-initializes genesis. After clean, start again with Steps 4-5.
Compare parallel execution throughput with and without BAL scheduling optimization.
bal-devnet-2 instance at $WORKDIR — uses BAL to pre-populate version maps and schedule transactions optimistically$WORKDIR-nobal — sets IGNORE_BAL=true to force dependency-tracking scheduling pathBoth instances sync the same chain, enabling direct throughput comparison.
| Service | Port | Protocol |
|---|---|---|
| Erigon HTTP RPC | 8945 | TCP |
| Erigon Engine API (authrpc) | 8951 | TCP |
| Erigon WebSocket | 8946 | TCP |
| Erigon P2P | 30703 | TCP+UDP |
| Erigon gRPC | 9490 | TCP |
| Erigon Torrent | 42469 | TCP+UDP |
| Erigon pprof | 6460 | TCP |
| Erigon metrics | 6461 | TCP |
| Lighthouse P2P | 9100 | TCP+UDP |
| Lighthouse QUIC | 9101 | UDP |
| Lighthouse HTTP API | 5352 | TCP |
| Lighthouse metrics | 5464 | TCP |
Create working directory and copy config:
NOBAL_DIR=${WORKDIR}-nobal
mkdir -p $NOBAL_DIR/erigon-data $NOBAL_DIR/lighthouse-data
cp -r $WORKDIR/testnet-config $NOBAL_DIR/
cp $WORKDIR/genesis.json $NOBAL_DIR/
Build a binary with IGNORE_BAL support (requires bal-devnet-2 branch with commit 45625d09+):
# Build from bal-devnet-2 branch (or use existing binary if already up to date)
make erigon
Initialize genesis:
./build/bin/erigon init --datadir=$NOBAL_DIR/erigon-data $NOBAL_DIR/genesis.json
Create start scripts — same as Instance A but with:
export IGNORE_BAL=true in start-erigon.shbal-devnet-2-nobal-lighthouse--execution-endpoint=http://127.0.0.1:8951 in Lighthouse--disable-enr-auto-update in Lighthouse (second instance on same host)Start Instance B (erigon first, then Lighthouse):
cd $NOBAL_DIR && nohup bash start-erigon.sh > erigon-console.log 2>&1 &
# Wait for jwt.hex
cd $NOBAL_DIR && nohup bash start-lighthouse.sh > lighthouse-console.log 2>&1 &
Once both instances reach chain tip, compare at-head execution metrics:
| Metric | Source | What it measures |
|---|---|---|
gas/s | Execution log lines | Raw execution throughput |
repeat% | Execution log lines | Speculative re-execution rate (lower = better dependency prediction) |
abort | Execution log lines | Number of aborted transactions per batch |
invalid | Execution log lines | Transactions invalidated by conflict detection |
blk/s | Execution log lines | Block processing rate |
Expected: BAL instance should have lower repeat% and abort counts because BAL pre-populates the version map, reducing false conflicts. The gas/s difference shows the net throughput impact.
# Side-by-side log comparison
echo "=== BAL (Instance A) ===" && \
grep -E "parallel (executed|done)" $WORKDIR/erigon-data/logs/erigon.log | tail -3 && \
echo "" && \
echo "=== No-BAL (Instance B) ===" && \
grep -E "parallel (executed|done)" ${WORKDIR}-nobal/erigon-data/logs/erigon.log | tail -3
# Stop Instance B
docker stop bal-devnet-2-nobal-lighthouse 2>/dev/null
pkill -f "datadir.*bal-devnet-2-nobal/erigon-data"
# Optionally remove data
rm -rf ${WORKDIR}-nobal
| Problem | Solution |
|---|---|
| JWT auth fails | Ensure erigon started first and jwt.hex exists. Lighthouse must mount the same file. |
| No EL peers | Check firewall allows port 30403. Try adding --nat=extip:<your-ip>. |
| No CL peers | Check firewall allows port 9100/9101. ENR bootnodes may have changed — re-fetch from inventory. |
| "Head is optimistic" | Normal during initial sync. Erigon is behind Lighthouse. Will resolve as erigon catches up. |
| Engine API timeout | Check erigon is running and authrpc port 8651 is accessible. |
| Port conflict | Check `ss -tlnp |