fix(l1): advertise the earliest block we can actually serve - #7210
Conversation
Three places hardcoded earliest_block to 0: the shared eth/69+ handshake status (rlpx/eth/status.rs), eth/70's own status struct, and BlockRangeUpdate, which is the ongoing half of the same advertisement. Every eth/69+ peer was therefore told we hold history from genesis. That is already untrue on any snap-synced node, where the earliest retained block is the pivot, and peers use the advertised range to decide what to request. It becomes materially wrong with history pruning (#6673), where the earliest block moves continuously and a stale handshake value would be wrong within hours. Read the value from the store instead. get_earliest_block_number is async while these constructors were sync, so they and their four handshake call sites become async; there is no cached sync accessor for it the way there is for the latest block.
|
🤖 Kimi Code ReviewThe PR correctly fixes a protocol honesty issue where nodes were unconditionally advertising Correctness & Safety
Code Quality
Minor Observations
Verdict Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt |
🤖 Codex Code Review
No other correctness or EVM/consensus issues stood out in the touched code. I could not run the Rust tests in this environment: Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
🤖 Claude Code ReviewReview: PR 7210 — Advertise the earliest block we can actually serveSummary: Replaces hardcoded What's good
Findings
Both points are low-severity / forward-looking rather than blocking — the change as written is correct for the current (non-pruned) system. Automated review by Claude (Anthropic) · sonnet · custom prompt |
Lines of code reportTotal lines added: Detailed view |
Motivation
Three places hardcoded the advertised earliest block to
0:crates/networking/p2p/rlpx/eth/status.rs:69crates/networking/p2p/rlpx/eth/eth70/status.rs:108crates/networking/p2p/rlpx/eth/update.rs:33BlockRangeUpdate— the ongoing half of the same advertisementSo every eth/69+ peer was told we hold history from genesis. That is already untrue on any snap-synced node, where the earliest retained block is the pivot, and peers use the advertised range to decide what to request from us — meaning we invite requests we then answer with empty replies.
It gets materially worse with history pruning (#6673): the earliest block moves continuously, so a hardcoded handshake value is wrong within hours of starting, and
BlockRangeUpdateexists precisely to keep peers current as the range moves.Description
Reads the value from the store in all three places.
get_earliest_block_numberis async (crates/storage/store.rs:1256) while these constructors were sync — there is no cached sync accessor for it the wayget_latest_block_numberhas one (:1275, backed bylatest_block_header). So the constructors and their four handshake call sites inrlpx/connection/server.rsbecome async. The alternative, caching earliest in memory alongside latest, is a larger change for no benefit on a path that runs once per handshake.Tests
Three tests in
crates/networking/p2p/rlpx/eth/status.rs:BlockRangeUpdatereads the field from the store rather than hardcoding it, and the result still satisfiesvalidate'searliest <= latestinvariant0, so this is a no-op for full-history nodesNote the second test deliberately uses
earliest = 0on a genesis-only store: setting a non-zero earliest above the latest block manufactures a range thatvalidatecorrectly rejects, which is a state a real node cannot reach.