Repository navigation
fix(cli): make discv5 opt-in on node again - #637
Conversation
Making discovery always on for both chains broke `make run-devnet`. The lean-quickstart devnet runs every node with `--network host` and passes no `--discovery.port`, so every node tried to bind the default UDP 9000. The first one got it, and the others exited at startup with "failed to bind discovery socket on 0.0.0.0:9000: Address already in use". With one validator of three left, the chain never justified. Only beacon needs discovery on unconditionally, because published mainnet bootnode ENRs carry no `quic` entry and cannot be dialed statically. A lean network has no other discv5 speakers, so a crawl there finds only other ethlambda nodes. Lean gets back the `--discovery.enable` switch that main still has, off by default. It lives in `LeanOptions`, so `beacon` rejects it rather than accepting a flag it would ignore. Without the flag, `P2P::spawn` gets `None`, binds no discovery socket and never schedules the dial loop. The UDP clash check and the ban on `--gossipsub-port 0` only apply when discovery runs, since otherwise no socket is bound and no ENR is published.
🤖 Claude Code ReviewReview: PR 637, make discv5 opt-in on
|
🤖 Kimi Code ReviewI'll review this PR which makes discv5 peer discovery opt-in for SummaryThe PR is well-structured and addresses a real operational need: co-located devnet nodes binding the same default UDP port. The core change is sound— However, I've identified several issues ranging from minor code quality concerns to potential correctness problems. Issues Found1. Redundant
|
🤖 Codex Code ReviewOverall this looks solid. The PR cleanly makes discovery optional for
One thing I’d still flag:
Nice touch:
I couldn’t run the targeted tests because Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
pablodeymo
left a comment
There was a problem hiding this comment.
LGTM. Beacon behavior is unchanged, the flag matches main's, and the dial loop really never runs without it. A few non-blocking nits:
dial_tickgetstarget_peersfrom the caller and then unwrapsserver.discoveryagain; theif let Someblocks atdial.rs:318anddial.rs:353can't fail. Readingtarget_peersinsidedial_tick, or anexpectwith the reason, would make the invariant explicit.- Maybe a
warn!when--discovery.*flags are passed tonodewithout--discovery.enable, since they're silently ignored. - The
mod banner/mod beaconreorder also fixes the base's fmt failure; worth a line in the description. - Could you confirm a 3-node
make run-devnetfinalizes before merging? That was the motivating failure.
…-63-64-633-636-638-gloas-live Blob-carrying block production and publication, and the operation pool, on top of the gloas follower. Conflicts were mostly additive (seen caches, verdict kinds, gossip reasons, fixture handlers, docs). Beyond the markers: operation rules read the registry through `validator_count()`, the fork-boundary discovery update skips a node with discovery off (#637), columns are gossiped under the block slot's digest and operations under the wall-clock slot's, and RPC wraps fulu sidecars into the fork enum `publish_beacon_block` now takes. Operations are ignored under a gloas head: #646's rules cover electra and fulu shapes only.
…. Since #637 made discovery opt-in on node, P2P::local_enr is None without it, as no record is published; the identity handler already answers with empty network fields in that case.
…live Brings in #637, which makes discovery opt-in and `P2PServer::discovery` an `Option`. Conflicts kept both sides: `DiscoveryState` gets both `filter()` and `target_peers()`, and startup schedules the first dial tick only with discovery on while still kicking `AdvanceForkSchedule`. The fork-digest crossing in `beacon/transition.rs` now updates the admission filter only when discovery is running, since without it there is no peer table to admit records into.
🗒️ Description / Motivation
make run-devneton this branch does not finalize. The lean-quickstart devnet runs every node with--network hostand passes no--discovery.port, and discv5 is currently always on for both chains. So every node tries to bind the default UDP 9000. The first node gets it, and the others exit at startup:With 3 nodes, only
ethlambda_0survived. It holds one validator of three, so it saw only its own blocks (the head moved every third slot) andjustified_slotstayed at 0. The aggregator was one of the nodes that died.Only
beaconneeds discovery on unconditionally, because published mainnet bootnode ENRs carry noquicentry and cannot be dialed statically. A lean network has no other discv5 speakers, so a crawl there finds only other ethlambda nodes. This PR givesnodeback the--discovery.enableswitch thatmainstill has, off by default.What Changed
bin/ethlambda/src/cli.rs--discovery.enableflag (LeanOptions::discovery_enable, defaultfalse).Network::discovery_enabled()is the single source of truth: the flag on lean, alwaystrueon beacon. Port validation moves toOptions::validate_ports(), which applies the discovery rules only when discovery runsbin/ethlambda/src/main.rsDiscoverySpawnConfigonly when discovery is enabled. Rewords the missing--bootnodeswarning to mention the flagcrates/net/p2p/src/lib.rsP2P::spawntakesOption<DiscoverySpawnConfig>andP2PServer.discoveryis anOption<DiscoveryState>, the same shape asmain.Nonebinds no socket and never schedules the firstDiscoverPeerstickcrates/net/p2p/src/discovery/dial.rstarget_peersas an argument instead of reading it from the discovery state. The refill step is extracted intorefill_candidatesso the borrow of the optional state does not span the dial's.await.forget_discovered_peerstill drops custody when discovery is offdocs/,CLAUDE.md,Dockerfilebeacon, opt-in fornode"Correctness / Behavior Guarantees
beaconis unchanged. It always runs discovery and runs the same port checks. It now rejects--discovery.enablewith a usage error instead of accepting a flag it would ignore.nodewithout--discovery.enablebinds no discovery socket, publishes no ENR and never runs the dial loop. It peers from--bootnodesalone, asnodedoes onmain.--discovery.portis not checked against--gossipsub-port, and--gossipsub-port 0is accepted, since no ENR names it. The TCP clash check against--api-port/--metrics-portapplies either way. It now skips0explicitly, because a0gossip port can reach it.--discovery.enablehas the same name and semantics as onmain, so launch commands carry over between the two branches.Tests Added / Run
The port tests in
cli.rsused to check that discovery was always on fornode. The ones that test discovery-on rules now pass--discovery.enable, and these tests are new:discovery_is_opt_in_on_node_and_always_on_on_beaconbeacon_has_no_discovery_enable_flagwithout_discovery_the_discovery_port_is_not_checkedgossipsub_port_zero_is_accepted_without_discoveryport_zero_never_counts_as_a_clash, which now covers both settingsCommands run:
make fmt,make lintcargo test --profile release-fast -p ethlambda --bins: 223 passedcargo test --profile release-fast -p ethlambda-p2p --lib: 207 passedThis has not been run on a local devnet yet.
✅ Verification Checklist
make fmt: cleanmake lint(clippy with-D warnings): cleanmake test: only the unit tests of the two touched crates were run (see above)