Skip to content

fix(web)[gloas]: flag serving checkpoint by block root, not epoch#244

Open
barnabasbusa wants to merge 1 commit intobbusa/fix-list-finalized-slots-underflow-gloasfrom
bbusa/fix-checkpoint-flag-root-match-gloas
Open

fix(web)[gloas]: flag serving checkpoint by block root, not epoch#244
barnabasbusa wants to merge 1 commit intobbusa/fix-list-finalized-slots-underflow-gloasfrom
bbusa/fix-checkpoint-flag-root-match-gloas

Conversation

@barnabasbusa
Copy link
Copy Markdown
Contributor

Summary

Stacked on top of #242 (targeted at release/gloas) so a gloas-based build picks up both the slots-list underflow fix and the flag-rendering fix in a single rebuild.

Same change as #243 (targeted at master).

The historical-checkpoints table flags the row currently being served. Previously it matched by epoch (status.data.finality.finalized.epoch === slot.epoch), which has two problems:

  1. Head/serving drift. The slots list is built from d.head (majority-decided finality) while status.data.finality comes from d.servingBundle (last fully-downloaded bundle). When bundle downloads lag — typical on short-lived kurtosis gloas devnets where bundle fetches may retry — d.head advances while d.servingBundle stays behind. Result: the slots list contains rows for epochs that aren't yet serving, so the flag appears on a non-top row or disappears until the bundle catches up.
  2. Epoch is ambiguous. Two different block roots could share the same epoch across restarts/reorgs. Block root is the semantically correct identifier for "the bundle we're serving."

Switch to slot.block_root === status.finality.finalized.root, with a fallback to the old epoch comparison for rows whose block_root hasn't been populated yet.

Merge order

Once #242 lands on release/gloas, rebase this PR onto release/gloas and flip its base. If #242 is merged into a squash commit that changes, rebase first.

Test plan

  • npx tsc --noEmit clean
  • npm run lint clean
  • Manual: rebuild image from this branch, point at a kurtosis gloas enclave, verify the flag renders on the row whose block_root matches status.data.finality.finalized.root

The historical-checkpoints table flags the row currently being served by
the checkpointz instance. It did this by comparing each row's epoch
against `status.data.finality.finalized.epoch`.

Two issues:

1. The slots list is built from `d.head` (majority-decided finality), but
   the status's `finality.finalized` is `d.servingBundle` (the last
   fully-downloaded bundle). When bundle downloads lag — e.g. after an
   upstream blip or on short-lived devnets — `d.head` advances while
   `d.servingBundle` stays behind, so the slots list contains rows for
   epochs that don't yet have a serving bundle. The flag then either
   appears on a non-top row with no explanation or disappears entirely
   until the bundle catches up.
2. Epoch-only comparison is ambiguous in principle (two different roots
   can share the same finalized epoch across restarts / reorgs, however
   rare post-finality). Matching by block root is the semantically
   correct signal: "which row's bundle is the one we're serving".

Prefer matching by `slot.block_root === status.finality.finalized.root`
and fall back to the old epoch-based comparison for rows whose
block_root hasn't been populated yet.
@barnabasbusa barnabasbusa requested a review from samcm as a code owner April 21, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant