Repository navigation
feat(sentry): fetch Gloas-aware v2 debug fork choice - #900
Merged
Merged
Conversation
The sentry now fetches GET /eth/v2/debug/fork_choice (ethereum/beacon-APIs#615), which returns one node per (block root, payload status) pair, and falls back to v1 for beacon nodes that do not serve it (retrying v2 hourly). Since Gloas, the v1 endpoint returns up to three indistinguishable nodes per block on some clients, and none of them report payload_status in extra_data, so ForkChoiceNodeV2's payload_status was never set. ForkChoiceNodeV2 gains the v2 fields: parent_payload_status and the Payload Timeliness Committee vote counts. ForkChoiceV2 gains the fork choice store's extra_data (e.g. the unrealized justified checkpoint), from both endpoints. All additive, so event names, Kafka topics and downstream routes are unchanged. Consumers converting to the go-eth2-client v1 shape still see the new fields in extra_data, and a node without extra data no longer panics that conversion. Bumps github.com/ethpandaops/go-eth2-client to the fork choice v2 branch (ethpandaops/go-eth2-client#60). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picks up decoding unrecognised validities (Lighthouse's not_yet_revealed for unrevealed Gloas payloads) as unknown instead of failing the whole fork choice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
The sentry now prefers GET /eth/v2/debug/fork_choice with an hourly-retried v1 fallback, and ForkChoiceV2 (proto + conversions) carries the Gloas parent_payload_status/PTC counts plus the store extra_data and the JSON-null panic fix. I traced the fetch/fallback control flow, every snapshot consumer, the v1↔v2 round trip, the enum mapping against consensus-specs and the pinned go-eth2-client constants, and the generated vtproto; the change is internally consistent and additive, and the dependency bump is clean on OSV.
Reviewed 11 changed file(s) @ ede1de64 — no blocking issues found.
"Debugging is twice as hard as writing the code in the first place." — Brian Kernighan
Bump go-eth2-client to ethpandaops/go-eth2-client#60 as aligned with ethereum/beacon-APIs#615 as merged: - Nodes carry justified and finalized checkpoints. They are kept as the new ForkChoiceNodeV2 justified_checkpoint / finalized_checkpoint fields and, as before, as justified_epoch / finalized_epoch, and are round-tripped into extra_data for consumers of the v1 shape. - Weight and the PTC counts are always set. go-eth2-client now rejects v2 responses that do not follow the spec, which is every client today. Any v2 failure, not only an unsupported endpoint, now falls back to v1 for forkChoiceV2RetryInterval, so such nodes keep producing fork choice data without a warning on every fetch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # go.mod # go.sum
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
samcm
approved these changes
Oct 8, 2026
This comment has been minimized.
This comment has been minimized.
Review follow-ups: - Back off to v1 for an hour only when the node lacks the endpoint or its v2 response does not follow the spec (go-eth2-client's ErrInvalidResponse). A timeout, 5xx or connection error falls back to v1 for that fetch only, and a cancelled fetch returns without falling back. - Move the fallback into fetchForkChoiceWithFallback and test it: v2 served, each failure kind, the back-off window, no provider, v1 errors and cancellation. - Decoded v2 values take precedence over a client's extra_data under the same keys, for the counts and checkpoints as for payload_status. - Test the null node extra_data round trip; note that a re-org event's before/after snapshots can come from different endpoints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Savid
added a commit
to ethpandaops/forky
that referenced
this pull request
Oct 8, 2026
go-eth2-client v0.1.10 decodes GET /eth/v2/debug/fork_choice strictly to ethereum/beacon-APIs#615 as merged, so every node carries its checkpoints, PTC counts and parent payload status. - ForkChoiceFromV2 maps the spec's node checkpoints, Gwei weight and plain counts onto forky's nodes, then runs the shared NormalizeV2. - Xatu events convert straight to forky's nodes, keeping values a sentry did not send unset (rather than zero) for NormalizeV2 to fill in. Node checkpoints from ethpandaops/xatu#900 are read, falling back to the epoch fields older sentries send. - v1: Lighthouse's not_yet_revealed now decodes as its own validity; it is still shown as optimistic, as is the older unknown + extra_data form. - The beacon node source backs off v2 for an hour only for nodes without the endpoint or with a non-spec response (ErrInvalidResponse); other failures fall back to v1 for that fetch. - Empty extra data is normalised to nil, as forky stores it. - Tests: a spec-shaped fixture derived from the Teku capture; the pre-spec client captures now exercise NormalizeV2 on partial nodes. Bumps go-eth2-client to v0.1.10 and xatu to ethpandaops/xatu#900. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Since Gloas activated on Sepolia, the sentry's fork choice events (which feed forky through
xatu-internal-kafka-vector-forky) lose the payload information:GET /eth/v1/debug/fork_choice. On Gloas, Teku and Lodestar return three v1 nodes per block (pending/empty/full) and Nimbus two, with nopayload_statusto tell them apart. Production forky on Sepolia currently receives Teku frames with 266 nodes for 89 blocks.ForkChoiceNodeV2.payload_statusis read from v1extra_data["payload_status"], which no client sets, so it is never populated.What
GET /eth/v2/debug/fork_choice(ethereum/beacon-APIs#615, merged 2026-10-07), one node per(block_root, payload_status), and falls back to v1 when v2 fails. Nodes that cannot serve v2 — no endpoint (Lighthouse 400, Nimbus 404) or a response that doesn't follow the spec, which go-eth2-client rejects withErrInvalidResponse(Teku, Prysm and Lodestar today) — use v1 for an hour before v2 is retried; any other v2 failure (timeout, 5xx) falls back for that fetch only, and a cancelled fetch returns without falling back. The fallback isfetchForkChoiceWithFallback, unit-tested for each case. Uses the newForkChoiceV2Providerfrom feat: add GET /eth/v2/debug/fork_choice and keep fork choice store extra data go-eth2-client#60 via the beacon node'sService(), so noethpandaops/beaconchange is needed.ForkChoiceNodeV2:parent_payload_status(same enum aspayload_status: EMPTY=0, FULL=1, PENDING=2, matching the spec'sPAYLOAD_STATUS_*),payload_attester_count,payload_availability_yes_count,payload_data_availability_yes_count, and the node'sjustified_checkpoint/finalized_checkpoint(whose epochs also filljustified_epoch/finalized_epoch, as for v1 nodes).ForkChoiceV2.extra_data: the fork choice store's values (unrealized justified/finalized checkpoints, proposer boost root, …), kept from both endpoints.NewForkChoiceV2FromGoEth2ClientV2.AsGoEth2ClientV1ForkChoiceround-trips the new fields (including the node checkpoints) into nodeextra_dataand the storeextra_dataonto the v1 type, so existing consumers (forky 1.0.2) still see them. Also fixes a panic in that conversion for nodes without extra data (encoded as JSONnull).Verified
go testandgolangci-lint(CI setup) pass.parent payload status missing, Prysm/Lodestarfork choice data missingas one warning each), and every node kept producingBEACON_API_ETH_V1_DEBUG_FORK_CHOICE_V2events from v1.Until clients implement the merged spec, events come from v1, so the payload status forky needs is still missing, as it is today. It arrives automatically, within the retry interval, once a client's v2 response follows the spec.
Notes for rollout
Deploy forky first. Production forky (1.0.2) decodes events with strict
protojson.Unmarshal, so the new fields (storeextra_data, which Prysm and Nimbus send even on v1, and the node fields) would make it drop whole batches. forkyrelease/glamsterdam-sepoliadecodes withDiscardUnknownand understands the new fields; roll it out before the server/sentries.Event size: v2 has a node per payload status. Teku's Sepolia event is ~425KB as protojson (under Kafka's default 1MB
max.message.bytes), but fork choice trees grow during non-finality, so it's worth checking broker/topic and Vector/ingress body limits for the fork choice topics.payload_statusfrom the v1extra_dataheuristic is kept for any client that starts reporting it there.go-eth2-client#60 decodes v2 strictly to the spec; its description has a table of where each client's current response falls short.
go-eth2-client is v0.1.10, which includes feat: add GET /eth/v2/debug/fork_choice and keep fork choice store extra data go-eth2-client#60.
🤖 Generated with Claude Code