feat(el): default execution clients to discv5-only with ENR bootnodes - #1461
feat(el): default execution clients to discv5-only with ENR bootnodes#1461barnabasbusa wants to merge 4 commits into
Conversation
81388da to
e78d854
Compare
CI statusGreen: The only genuine failure is No rbuilder tag exists that parses ENRs. It needs rebasing on reth ≥
Earlier runs in this PR were also mostly self-inflicted: |
|
Made Rationale: the builder runs Coverage is not lost: Restore it here once |
Discv5 bootstraps from ENRs, not enodes. Besu discards its enode bootnode list entirely once discv5 is enabled, and nimbus-eth1 now hard-disables discv4 (status-im/nimbus-eth1#4582), leaving its enode list feeding a protocol that no longer runs. Switch the EL bootnode plumbing from enodes to ENRs and turn discv4 off: geth --discovery.v4=false --discovery.v5=true erigon --discovery.v4=false --discovery.v5=true ethrex --p2p.discv4=false --p2p.discv5=true reth --disable-discv4-discovery nethermind --Discovery.DiscoveryVersion=V5 besu --discovery-mode=V5 nimbus no flag needed, discv4 is disabled upstream Bootnodes come from each peer's ENR on the kurtosis/shadowfork path and from el_enrs.txt on the named-devnet path. Entries without an ENR are skipped rather than emitted as empty strings, so a client that cannot report one is simply not used as a bootnode source. Nethermind is one such client: its admin_nodeInfo has no enr field, and Kurtosis' extractor errors on a missing field rather than returning empty. ethereumjs is left on discv4 and enodes: it has no discv5 implementation.
… discv5-only
Verified by running each image:
hyperledger/besu:latest leaves --discovery-mode=V5 unmatched
ghcr.io/paradigmxyz/reth rejects enr: bootnodes with
'Failed to parse url: no host specified'
nethermind/nethermind:latest exits 1 with
'PublicKey should be 64 bytes long'
besu --discovery-mode landed in #10800 (2026-07-22) and reth enr: bootnodes
via CLI in #26448 (2026-07-29); neither is in a release. Revert all three
pins to the upstream images once the changes ship.
The mev builder runs ethpandaops/reth-rbuilder, whose newest build predates reth #26448, so it rejects enr: bootnodes and cannot run discv5-only. Because run_with_args does not set fail-fast: false, that one leg also cancels mix-public and mix-with-tools, taking out 3 of 8 legs. nightly.yml globs .github/tests/*.yaml with continue-on-error: true, so mev.yaml still runs there. Restore it here once reth-rbuilder is rebased on reth >= c505ed2.
11b1e81 to
ebcba8e
Compare
reth's discv5 defaults to UDP 9200 (DEFAULT_DISCOVERY_V5_PORT), while --discovery.port only sets the discv4 socket. The port spec declares udp-discovery on the discovery port, so with discv4 disabled reth was advertising an ENR pointing at an undeclared, unpublished port. Container-to-container traffic inside an enclave is open so this still peered, but with port_publisher enabled, or behind a real host firewall, reth's discv5 would be unreachable. Confirmed via admin_nodeInfo on a discv5-only enclave: reth reported ports.discovery 9200 while every other EL reported 30303.
|
Found a real bug while checking what
Visible in It still peered in that run only because container-to-container traffic inside an enclave is unrestricted. With Fixed by passing Also worth noting from the same dump: |
Draft — the named-devnet path needs
el_enrs.txt, andmev.yamlis blocked on an upstream rbuilder rebuild. See Depends on and Known blockers.Why
Discv5 bootstraps from ENRs, not enodes, and two clients make this mandatory rather than cosmetic:
Invalid ENR bootnode: ... must start with 'enr:'.The other clients accept
enr:in their bootnode flag too, so ENRs are a strict superset.What
Discv4 off, discv5 on:
--discovery.v4=false --discovery.v5=true--discovery.v4=false --discovery.v5=true--p2p.discv4=false --p2p.discv5=true--disable-discv4-discovery--Discovery.DiscoveryVersion=V5--discovery-mode=V5Bootnodes now come from ENRs on both paths:
ctx.enr, which meant plumbing the ENR through besu, reth and nimbus (get_enode_enr_for_node); geth, erigon and ethrex already had it.get_devnet_el_enrs()readingel_enrs.txt, mirroringget_devnet_enodes().bootstrap_nodes.txtis CL beacon ENRs and stays reserved for the CL launchers.Entries without an ENR are filtered out rather than emitted as empty strings, so a client that can't report one isn't used as a bootnode source instead of corrupting everyone's list.
ethereumjsis deliberately untouched: no discv5 implementation at all (config.tshas onlydiscV4/discDns), so it keeps discv4 and enodes and will not peer with the discv5-only clients.Default image bumps — all temporary
Every one of these was verified by running the image; three of seven ELs need builds newer than their current release:
hyperledger/besu:latest(26.7.0)--discovery-mode=V5unmatchedethpandaops/besu:main--Xv5-discovery-enabled)ghcr.io/paradigmxyz/rethinvalid value 'enr:...': Failed to parse url: no host specifiedethpandaops/reth:mainenr:bootnodes —2.4.1-dev (c505ed2)nethermind/nethermind:latestPublicKey should be 64 bytes longethpandaops/nethermind:masterDiscv5 bootnodes accepted: 1Enabling commits, none of which are in a release:
--discovery-mode— #10800, 2026-07-22enr:bootnodes via CLI — #26448, 2026-07-29All three image pins should revert to the upstream images once these ship in releases.
Known blockers
mev.yamlcannot pass yet. The builder runsethpandaops/reth-rbuilder:develop, whose newest build is 2026-07-17 — 12 days before reth #26448. Verified directly: it rejectsenr:bootnodes withFailed to parse url: no host specified. There is no rbuilder tag that works. It needs rebasing on reth ≥c505ed2; there's no workaround in this package, since putting the builder back on discv4 + enodes would isolate it from the discv5-only mesh anyway.admin_nodeInfohas noenrfield —BuildNodeInfo()sets Enode/Id/Ip/ListenAddress/Ports/Protocols only. Kurtosis' extractor errors hard on a missing field rather than returning empty, so nethermind stays onget_enode_for_nodeand is excluded as a bootnode source. It still peers fine using other nodes' ENRs, and shouldn't be madeprimary_bootnode. Fixing it upstream needsINodeRecordProvidermoved intoNethermind.Networkfirst —Nethermind.JsonRpc→Nethermind.Network.Discoverywould be a circular project reference.Depends on
ethpandaops/ansible-collection-general#568 adds
el_enrs.txt. Until it lands and devnet metadata is regenerated, the named-devnet path has no ENR file to read. The kurtosis/shadowfork path works today.Testing
kurtosis lintclean acrosssrc/.7-EL enclave (geth, besu, erigon, reth, nethermind, nimbusel, ethrex) discv5-only with ENR bootnodes — all seven peered and began syncing:
The same run on unmodified devnet-7 images had besu and reth both
Exited (2). Nethermind takes ~2 min to find its first peer (slow discv5 lookup cadence) but does get there.