Skip to content

api,web: use the chain's measured slot time for ledger epoch ETAs - #792

Merged
nikw9944 merged 5 commits into
mainfrom
nikw9944/infra-2318
Aug 24, 2026
Merged

api,web: use the chain's measured slot time for ledger epoch ETAs#792
nikw9944 merged 5 commits into
mainfrom
nikw9944/infra-2318

Conversation

@nikw9944

Copy link
Copy Markdown
Contributor

Summary of Changes

  • Epoch ETAs now use each chain's own slot time, measured from the performance samples the ledger fetch already makes, instead of a hardcoded 0.4s.
  • 0.4s was wrong on both dashboards. Solana mainnet is stepping 400ms → 350ms → 200ms through the SIMD-0525 stages, so a 350ms epoch read about six hours long. The DoubleZero ledger isn't governed by SIMD-0525 but beats its own 400ms target by ~8% — it lands 432k-slot epochs in ~44h, not 48h — so projecting at 400ms put the boundary up to ~4h late right after a rollover.
  • Measuring rather than hardcoding is what makes one code path correct for both chains: there is no authoritative constant to copy for the DoubleZero ledger, and Solana would otherwise need an edit per remaining SIMD stage. Costs no extra RPC call. Rationale in malbeclabs/infra#2318.
  • The measured value is published as slot_duration_sec, so the Epoch card's "started N ago" figure derives from it instead of keeping its own copy of 0.4 — both figures on that card now come from one number.
  • Fixes malbeclabs/infra#2318

Expect the DoubleZero epoch numbers to move on deploy. The ETA and "started N ago" each drop ~8%, since both are a slot count times the same measured slot time. That's the fix landing.

Testing Verification

  • TestSlotDurationFromSamples covers the derivation against each real-world rate (Solana 400/350/300/200ms, the DZ ledger's ~367ms), that samples are summed across the window rather than averaged per sample, and that both [0.15s, 1.0s] bounds accept their exact boundary value — an off-by-one there silently discards legitimate readings.
  • TestFetchLedgerData_EpochETAUsesMeasuredSlotDuration runs a fake RPC at double the slot rate and asserts the ETA halves; under the old constant both rates reported the same number.
  • TestFetchLedgerData_UnusableSamplesUseTheCallersFallback asserts each chain reaches its own fallback from identical unusable samples, so a shared default can't pass.
  • No live-RPC check was possible from the build sandbox. After deploy, check slot_duration_sec on /api/dz/ledger and /api/solana/ledger — expect ~0.367 and ~0.400 (~0.350 once the epoch-1020 gate takes effect). The DZ ledger's numSlots semantics are the one thing not verified against a live endpoint; the guardrails bound the damage if it turns out mis-populated, and it would show up here.

Follow-ups (not in this PR)

  • multicast-group-detail-page.tsx:65 and topology/overlays/MulticastTreesOverlayPanel.tsx:124 still convert DZ slot deltas at a hardcoded 0.4 — same ~8% error, different data path.
  • ETA values now jitter slightly between refreshes. If that shows up in practice, the lever is a longer sample window (raise the limit on the existing call, keep TPS on the newest 10), not a tighter clamp.

@nikw9944 nikw9944 self-assigned this Aug 20, 2026
@nikw9944
nikw9944 marked this pull request as ready for review August 20, 2026 18:21

@ben-dz ben-dz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking.

Comment thread api/handlers/ledger.go Outdated
@nikw9944

Copy link
Copy Markdown
Contributor Author

Thanks Ben. Addressed the one optional note in abe78ea: GetDZLedgerRPCURL and GetSolanaRPCURL are now unexported. You were right that this diff orphaned them — I verified no callers remained outside ledger.go before renaming.

Nothing else changed. The branch is already on top of the latest main, so no rebase was needed.

@github-actions

Copy link
Copy Markdown

🔗 Preview: https://pr-792.data.malbeclabs.com

@nikw9944

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (through 5d8fe88) — force-push is that rebase, no code changes. Clean, no conflicts; the branch diff is still only the ledger slot-duration work.

Ben's one optional note remains addressed in the rebased api: unexport the ledger RPC URL getters commit. No other feedback outstanding.

@nikw9944
nikw9944 force-pushed the nikw9944/infra-2318 branch from 5bcd61a to 44757e3 Compare August 21, 2026 20:59
@nikw9944

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (through cd7c0f5) — force-push is that rebase, no code changes. Clean, despite #797 touching api/worker/workflow.go; both ledger page-cache entries came through unchanged.

Ben's optional note stays addressed in the rebased api: unexport the ledger RPC URL getters commit. Nothing else outstanding.

FetchLedgerData multiplied remaining slots by a hardcoded 0.4s for both the
Solana Overview and DoubleZero Ledger pages. Neither chain runs at 0.4s:
Solana mainnet is stepping 400ms -> 350ms -> 200ms through the SIMD-0525
stages and testnet is already at 200ms, while the DoubleZero ledger beats its
own 400ms target by ~8% and lands 432k-slot epochs in ~44h.

The rate is now derived from the performance samples the function already
fetches, sum(samplePeriodSecs) / sum(numSlots), so it tracks each chain with
no added RPC call and no edit per SIMD stage. Readings outside [0.15s, 1.0s],
or a sample window under 300s, fall back to a per-chain constant.

The value is published as slot_duration_sec so the Epoch card's "started N
ago" figure derives from it instead of keeping its own copy of 0.4.

Fixes #2318
- Drop the 300s sample-window floor. Its stated rationale (short windows
  dominated by RPC latency and jitter) doesn't hold: numSlots and
  samplePeriodSecs are both measured by the node, and a single 60s sample
  already spans ~150 slots, so it estimates within ~1%. Its only production
  effect was to substitute the hardcoded fallback exactly when an endpoint
  has few samples. The [0.15, 1.0] bounds already reject the degenerate
  shapes, including a node replaying history rather than keeping up.
- Pair each chain's RPC URL with its fallback constant once, in
  FetchDZLedgerData / FetchSolanaLedgerData, instead of at four call sites
  where a mismatched pair compiles silently and would have the same chain
  report two ETAs depending on whether the page cache was warm.
  fetchLedgerData and both constants are now unexported.
- slot_duration_sec is optional in the TS interface: a page-cache row
  written before this field existed is served back verbatim, so the web's
  0.4 fallback is reachable and shouldn't read as dead code.
- Fix the changelog's claim that "started N ago" grows. It and the ETA are
  both a slot count times the same slot time, so on DZ they both drop ~8%.
Drop what the code already says, and the per-environment slot times and
epoch/date pins that will be wrong within a stage or two. What stays is the
part a reader can't derive: agave's numSlots semantics, why the DZ fallback
is the observed rate rather than the nominal one, and why URL and fallback
are paired in one place.

Also fixes a stale assertion message in the supply test: its fake serves one
60s sample, not the ten an earlier draft had.
This diff moved their last outside caller, api/worker/workflow.go, onto the
FetchDZLedgerData / FetchSolanaLedgerData wrappers, leaving two exports with
no users beyond ledger.go.
@nikw9944
nikw9944 force-pushed the nikw9944/infra-2318 branch from 44757e3 to 591ab28 Compare August 24, 2026 17:40
@nikw9944

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (through 4462a22) — force-push is that rebase, no code changes. Clean, no conflicts; the branch diff is still only the ledger slot-duration work.

Ben's optional note stays addressed in the rebased api: unexport the ledger RPC URL getters commit. Nothing else outstanding.

@nikw9944
nikw9944 merged commit 6c3236f into main Aug 24, 2026
8 checks passed
@nikw9944
nikw9944 deleted the nikw9944/infra-2318 branch August 24, 2026 18:13
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.

3 participants