Skip to content

feat: Glamsterdam (gloas) support — fork registry, ePBS slot phases, payload lifecycle - #444

Merged
samcm merged 24 commits into
masterfrom
feat/glamsterdam-gloas
Jul 17, 2026
Merged

feat: Glamsterdam (gloas) support — fork registry, ePBS slot phases, payload lifecycle#444
samcm merged 24 commits into
masterfrom
feat/glamsterdam-gloas

Conversation

@samcm

@samcm samcm commented Jul 16, 2026

Copy link
Copy Markdown
Member

Fixes the crash on every fork-aware route for glamsterdam devnets: the fork registry carried a misspelled glaos placeholder while /api/v1/config already serves forks.consensus.gloas, so FORK_METADATA lookups returned undefined and the error boundary swallowed the page (reproducible on production lab today for any glamsterdam-devnet-6/7 slot). The placeholder becomes gloas with real Glamsterdam metadata, ForkLabel degrades gracefully for unknown future forks, and isForkAtOrAfter replaces string-equality fork gates (the blob/data-column chart only matched fulu exactly).

Slot structure is now specified once per fork as basis points of the slot duration, mirroring the consensus config deadlines (ATTESTATION_DUE_BPS_GLOAS 2500, AGGREGATE_DUE_BPS_GLOAS 5000, PAYLOAD_DUE_BPS/PAYLOAD_ATTESTATION_DUE_BPS 7500). 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 render Payload 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_block execution columns (served zero-filled by the block tables; needs an upstream join against the payload tables).

samcm added 23 commits July 16, 2026 15:37
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
samcm marked this pull request as ready for review July 17, 2026 05:23
@samcm
samcm requested a review from Savid as a code owner July 17, 2026 05:23
The playhead now reads minOfMaxes, which the fixture didn't provide.
@samcm
samcm merged commit d02c7c3 into master Jul 17, 2026
3 checks passed
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.

2 participants