Skip to content

Caplin GLOAS fork choice: maintain per-node weights via delta propagation instead of a per-attestation vote index #21704

@yperbasis

Description

@yperbasis

Background

#21694 wires GLOAS head selection (getHeadGloas) onto the incremental indexedWeightStore: votes are maintained in a directVotes index per attestation (IndexVote/RemoveVote), and weights are computed lazily by a subtree DFS per GetWeight. This is correct in steady state (differential test vs the full-scan store) and far faster than the previous O(V) full-scan — but it diverges from the canonical fork-choice design and keeps a per-attestation maintenance cost on the hot path.

#21698 removed that per-attestation index maintenance pre-GLOAS (where its result was never read). Under GLOAS it returns, because the index is maintained on every GLOAS attestation and getHeadGloas now reads it. #21694 trims it (allocation-free RemoveVote, no per-vote getCheckpointState), but RemoveVote is still an O(E) scan per attestation under the fork-choice lock.

What Prysm and Lighthouse do (verified on glamsterdam-devnet-5)

Both use the proto-array / doubly-linked-tree model:

  • Per attestation: O(1), no weight work — just record the validator's vote (current/next root + payload-present). Prysm ProcessAttestation updates f.votes[index]; Lighthouse process_attestation sets vote.next_root / next_payload_present.
  • Per head: delta propagation over a maintained per-node weight tree. Lighthouse apply_score_changes computes per-validator deltas from vote changes and applies them to node.weight, propagated up — O(nodes + changed votes). Prysm applyWeightChangesConsensusNode / ...PayloadNode recompute weight = balance + Σ children bottom-up.
  • (root, payload_status) handled per node. Lighthouse: each ProtoNode carries empty_delta / full_delta and attestation_score(payload_status). Prysm: a two-tier tree of consensus NodeEMPTY/FULL PayloadNode.

Net: votes stored per validator (cheap), per-node cumulative weights materialized incrementally; head = follow best-descendant; the debug dump is free.

Proposal

Adopt the delta model for Caplin GLOAS fork choice:

  1. Stop maintaining the directVotes index per attestation; keep votes in latestMessages (already O(1)/attestation).
  2. Maintain a per-node cumulative weight (with Empty/Full payload-status variants), updated by deltas computed from latestMessages changes at head time and propagated over the filtered tree — O(nodes + changed votes).
  3. getHeadGloas follows best-descendant over the maintained weights.

Benefits

Cost / notes

References

Metadata

Metadata

Assignees

Labels

CaplinCaplin: Consensus Layer, Beacon APIGlamsterdamhttps://eips.ethereum.org/EIPS/eip-7773performance

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions