feat: Glamsterdam (gloas) support — fork registry, ePBS slot phases, payload lifecycle - #444
Merged
Conversation
The fork registry carried a misspelled 'glaos' placeholder while networks already serve forks.consensus.gloas, so every fork-aware surface crashed on glamsterdam devnets (FORK_METADATA lookup returned undefined). Renames the placeholder to gloas with real Glamsterdam metadata (EIP-7732 ePBS + EIP-7805 FOCIL, execution fork amsterdam), gives ForkLabel a fallback so unknown future fork names degrade to a plain label instead of a crash, and adds isForkAtOrAfter so fork gates stop being string-equality checks that new forks silently miss (BlobDataColumnSpreadChart only matched fulu). Slot phases are now specified once per fork in basis points of the slot duration, mirroring the consensus config deadlines: pre-gloas keeps block/attestation/aggregation at 33/67%, gloas uses the ePBS structure (attestation 25%, aggregate 50%, payload reveal + PTC due 75%). getSlotPhases(fork) drives the live view phase bar.
Generated from a local cbt-api running the xatu-cbt gloas models (fct_block_payload_first_seen_by_node, fct_block_payload_available_by_node, fct_block_payload_ptc_vote[_head], fct_block_payload_bid, fct_payload_bid_highest_value_by_builder_chunked_50ms).
Gloas slots get a Payload card showing the winning builder bid, when sentries first saw the revealed envelope, when payload+blobs verified locally, and the PTC verdict. derivePayloadStatus classifies the slot (payload delivered / late / withheld) from PTC majority with sentry sightings breaking the late-vs-withheld tie; self-builds are detected by builder index == proposer index. Renders nothing before gloas.
…d race The payload card sat above the tab strip on every gloas slot, crowding the page. Gloas slots now get a dedicated Payload tab (hidden pre-gloas) holding the lifecycle summary and a Builder Bid Race chart — the fct_payload_bid_highest_value_by_builder_chunked_50ms series rendered through MevBiddingTimelineChart, whose title, anchor and y-axis label are now props so it serves both the relay-era and ePBS auctions.
On gloas networks the HUD swaps its relay-era MEV and Auction sections for the payload lifecycle: the Auction lane streams the on-chain builder bid race (bid count, distinct builders, best bid, first-bid time — negative when bids beat the slot start), and a Payload section shows envelope reveal timing across sentries, the revealing builder, and PTC votes with a delivered/late/withheld chip driven by derivePayloadStatus. Payload rows fade in as the replay clock crosses the envelope arrival; auction data shows immediately since bidding precedes the slot.
…lots The playhead derived maxSlot from maxOfMaxes, so the fastest-moving table could drag playback into slots the slower tables had no data for. Use minOfMaxes — the newest slot every table has landed. Per-slot queries also fetched once at slot start and cached for 60s, baking whatever partial state the pipeline had (one node on the map, a lone attestation chunk) into the whole replay. Slots younger than 48s now poll every 5s until settled, then keep the cache-forever behaviour.
The second attestation type gloas introduces — PTC payload attestations — now renders as its own arrivals chart under the committee attestation chart, fed by the new fct_payload_attestation_first_seen_chunked_50ms table and revealed progressively with the replay clock like everything else. Payload envelope sightings also join the map as a second purple-tinted wave, so the payload visibly washes over the sentry network after the block does. API client regenerated with the new endpoint.
…line The stacked mini-chart treatment for PTC payload attestations was cramped and unreadable. Both vote streams now share one MultiLine chart with a legend; the PTC series appears once votes actually exist, so pre-gloas networks and the first seconds of a slot stay single-series. The sidebar timeline gains the gloas events it was missing: payload envelope sightings (grouped by city like blocks) and PTC vote arrivals. Devnet sentries all sit in one datacenter city, which the sidebar rendered as a single anonymous Block row — city rows now carry their node count so one location no longer reads as one node.
Pure minOfMaxes froze the playhead entirely when a single table's bounds trailed by minutes. Prefer the intersection but never fall more than three slots behind the freshest table — near-head slots poll and backfill as the lagging table lands.
City aggregation collapsed every sentry in a datacenter into one anonymous row, which on devnets meant the whole fleet read as a single node. Block and payload sightings are now one row per node with the city as secondary text, on every network.
Per-node rows kept, but the visible label is the node's location, matching the established mainnet rendering; the node id rides along muted.
Node ids repeated the network name and nothing in the row could shrink, so content ran off the page. The network prefix is stripped, the location stays visible, and the node id truncates with the full value on hover.
Back to the city-grouped location rows master ships. The only sidebar changes left are additive: payload envelope rows in the identical shape, and PTC vote rows in the attestation-row shape.
EIP-7805 is not part of Glamsterdam — ePBS took the consensus headliner slot. A few leftover inclusion-list constants in the devnet config presets misled the description; the devnets expose no inclusion-list surface.
The Execution tab rendered zero-filled values on gloas slots because the beacon block no longer carries the payload. Payload facts from the new fct_block_payload table (bid commitment joined with envelope contents) overlay the block's execution columns, and fields that genuinely no longer exist CL-side (gas used, base fee, block number) are hidden rather than shown as zeros. The slots list gains a Payload column on gloas networks: the PTC's verdict per slot, Delivered or Absent, with the vote tally on hover.
The CL block carries no payload post-gloas, so txns/gas/base/block arrive zero-filled at the head. The Execution lane now shows just the blob count on gloas networks instead of misleading zeros.
The proposer pipeline lags the head, so requiring it before judging the payload left slots showing Awaiting data despite a full PTC verdict. Votes and envelope sightings are themselves proof a block existed.
One series per builder stops scaling long before the on-chain auction does. The ten strongest bidders by peak value keep individual series and the remainder collapses into a single field series carrying the best remaining bid per chunk, so hundreds of builders render as eleven lines and the fetch stays within one page.
The frontier table bounds chart data by the 50ms grid regardless of builder count: the ten strongest bidders keep individual series, the frontier renders as the best-bid line when builders were cut from the top list, and if the by_builder fetch ever truncates the chart degrades to the frontier alone instead of silently lying.
Parity with the live view: envelope propagation across sentries reuses BlockPropagationChart and PTC vote arrivals reuse AttestationArrivalsChart, both parameterized for title and anchor so the components serve either stream. The payload data hook also exposes raw PTC chunks.
Hourly PTC-judged delivery outcomes from fct_block_payload_status_hourly, reusing the proposal-status chart shape (same record structure). Self-gates by data presence, so pre-gloas networks never show it.
The trace timeline gains the two gloas phases it was missing: an envelope reveal span covering first-to-last sighting across sentries and a PTC vote span covering the vote arrival window, both fed by the payload data hook and only present post-gloas.
samcm
marked this pull request as ready for review
July 17, 2026 05:23
The playhead now reads minOfMaxes, which the fixture didn't provide.
Savid
approved these changes
Jul 17, 2026
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.
Fixes the crash on every fork-aware route for glamsterdam devnets: the fork registry carried a misspelled
glaosplaceholder while/api/v1/configalready servesforks.consensus.gloas, soFORK_METADATAlookups returned undefined and the error boundary swallowed the page (reproducible on production lab today for anyglamsterdam-devnet-6/7slot). The placeholder becomesgloaswith real Glamsterdam metadata,ForkLabeldegrades gracefully for unknown future forks, andisForkAtOrAfterreplaces string-equality fork gates (the blob/data-column chart only matchedfuluexactly).Slot structure is now specified once per fork as basis points of the slot duration, mirroring the consensus config deadlines (
ATTESTATION_DUE_BPS_GLOAS2500,AGGREGATE_DUE_BPS_GLOAS5000,PAYLOAD_DUE_BPS/PAYLOAD_ATTESTATION_DUE_BPS7500).getSlotPhases(fork)feeds the live view, which shows Block / Attestations / Payload / PTC on gloas networks.Slot detail gains a Payload card for gloas slots: winning builder bid (wei, self-build detection via builder index == proposer index), envelope first-seen and verified-available timing across sentries, and the PTC verdict with a derived status (delivered / late / withheld). Data comes from the new xatu-cbt ePBS tables (ethpandaops/xatu-cbt#297 +
release/glamsterdam-devnet-7); the API client is regenerated from a cbt-api carrying those models.Verified against production glamsterdam-devnet-7 data through the xcli hybrid stack: slot 12336 renders
Payload late(payload seen by 29 sentries at 5.5s, 9/70 PTC present votes) and healthy slots renderPayload delivered.Follow-ups deliberately not in this PR: ePBS lanes in the slot-detail trace timeline, bid-race chart on the live view, fork-aware phase gridlines in the NodeResources charts, and the gloas-era
fct_blockexecution columns (served zero-filled by the block tables; needs an upstream join against the payload tables).