Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/methodology/solana-tx-landing-active.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ We do **not** vary tip amount across cycles. A "tip elasticity" experiment is a
4. Capture `submit_slot = getSlot(commitment="processed")` and `submit_wallclock = time.Now()`.
5. POST the base64-encoded signed transaction to the service's documented submission endpoint (exact URLs published in the harness source) with `skipPreflight = true`, `maxRetries = 0`, `encoding = "base64"`. Per-service auth headers / query params are applied as documented.
6. Capture the returned signature (or fail-fast on RPC error).
7. Poll `getSignatureStatuses` on the public mainnet RPC every 1 second.
7. Poll `getSignatureStatuses` on the public mainnet RPC every 200 ms. The poll cadence is the measurement floor for `latency_ms`. We chose 200 ms because Solana's slot duration is ~400 ms and "confirmed" lands ~1-2 slots after inclusion (~400 ms-1 s realistic), so a 1 s poll quantizes everything into 1 s steps and erases differentiation between services. 200 ms gives 5x the resolution while staying within public RPC budget.
8. On status reaching `confirmationStatus = "confirmed"` or `"finalized"`, record `land_slot` from the response context and `land_wallclock = time.Now()`. Classify as **landed**.
9. If 60 seconds elapse without a non-null `confirmationStatus`, abandon the poll. Classify as **dropped** with reason `timeout`.
10. If the original submission returned a transport error (HTTP timeout, DNS, EOF, connection refused), classify as **dropped** with reason `network_error`. If the upstream returned HTTP 419 / 429 or a JSON-RPC error containing "rate limit" / "too many requests", classify as `rate_limited`. If the submission was rejected with a structured RPC error (`InstructionError`, `BlockhashNotFound`, etc.) or the on-chain status comes back with an `Err`, classify as `invalid`.
Expand DownExpand Up@@ -156,3 +156,4 @@ Sponsorship policy and the disclosure block live in [`solana-landing-tiered-arch
|---|---|---|
| v1.0 | 2026-05-21 | Initial pre-registration. V0-Lean scope : 5 services × 1 region × 1 / h. |
| v1.1 | 2026-05-21 | Pre-launch reconciliation with implementation : metric names from `ocb_solana_landing_*` to `solana_landing_probe_*` (matches sibling OCB benches), `rate_limited` added as 4th drop reason, latency_ms histogram bucket list adjusted to include 250 ms and 30 s, blockhash commitment rationale clarified, memo format clarified (`ocb-<cycle_id>-<service>-<mode>` where cycle_id is itself the 8-byte random hex shared across all per-service probes in the cycle), `solana_landing_probe_enabled` gauge added so dashboards distinguish "prober disabled" from "prober stuck". |
| v1.2 | 2026-05-23 | `getSignatureStatuses` poll interval reduced from 1 s to 200 ms after the first 7 days of live data showed all services collapsing to identical 1.0 s p50. The 1 s poll was the measurement floor (Solana confirmed status arrives in ~400 ms-1 s), so 200 ms restores 5x the resolution. Bench page queries also switched from `histogram_quantile` on the latency_ms histogram to `quantile_over_time` on the latency_ms gauge, since the histogram bucket list only had ~3 buckets in the 1-5 s zone where probes actually land, collapsing p50 to bucket midpoints. |
17 changes: 9 additions & 8 deletions src/components/distribution-chart.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,25 +101,23 @@ export function DistributionChart({
}
}}
title={methodologyTooltip(r, isOff)}
className={`py-3 cursor-pointer rounded-sm transition-colors hover:bg-paper-soft/40 ${
className={`grid grid-cols-[minmax(6rem,9rem)_1fr_auto] sm:grid-cols-[minmax(8rem,12rem)_1fr_auto] items-center gap-3 sm:gap-4 py-2.5 cursor-pointer rounded-sm transition-colors hover:bg-paper-soft/40 ${
isOff ? "opacity-40" : ""
}`}
>
<div className="flex items-center gap-2 mb-2 min-w-0">
{/* Identity column — logo + name on one line, no white gap above the track */}
<span className="flex items-center gap-2 min-w-0 text-[13px]">
<ProviderLogo slug={r.slug} name={r.name} size={18} />
<span
className={`font-serif font-semibold truncate text-[13px] ${
className={`font-serif font-semibold truncate ${
isOff ? "line-through decoration-1" : ""
}`}
style={{ color: isOff ? "var(--color-ink-faint)" : color }}
>
{r.name}
</span>
<span className="ml-auto label-mono text-ink-faint tabular shrink-0">
{fmtUnit(r.ms.p50, unit)}
</span>
</div>
{/* Track */}
</span>
{/* Track column — inline with the name so the row reads in a single line */}
<div className="relative h-4 rounded-sm bg-paper-soft">
{!isOff && (
<>
Expand All@@ -138,6 +136,9 @@ export function DistributionChart({
</>
)}
</div>
<span className="label-mono text-ink-faint tabular shrink-0 whitespace-nowrap">
{fmtUnit(r.ms.p50, unit)}
</span>
</li>
);
})}
Expand Down
19 changes: 9 additions & 10 deletions src/lib/views.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,16 +22,15 @@ export type ViewType =
const ALLOWED_BY_UNIT: Record<Benchmark["unit"], ViewType[]> = {
// distribution surfaces tail behaviour (p90/p99 vs p50) which is the
// signal users actually care about on latency / cost / yield benches.
ms: ["timeseries", "rankedBar", "distribution"],
s: ["timeseries", "rankedBar", "distribution"],
bps: ["timeseries", "rankedBar", "distribution"],
pct: ["timeseries", "rankedBar", "distribution"],
// donut only makes sense when each provider's value is a share of a
// meaningful total. count benches with market-share semantics
// (solana-tx-landing) get the most out of it; other count benches
// also render but the slices represent the relative size of each
// provider's footprint, which is still a useful read.
count: ["countLeaderboard", "rankedBar", "donut", "timeseries"],
// donut is offered everywhere too: on latency / pct / bps it reads as
// "share of the field's total p50", a perfectly valid (if unusual)
// comparison the reader can ignore if they don't want it. Putting the
// option behind the switcher gives the choice instead of guessing.
ms: ["timeseries", "rankedBar", "distribution", "donut"],
s: ["timeseries", "rankedBar", "distribution", "donut"],
bps: ["timeseries", "rankedBar", "distribution", "donut"],
pct: ["timeseries", "rankedBar", "distribution", "donut"],
count: ["countLeaderboard", "rankedBar", "donut", "distribution", "timeseries"],
};

/**
Expand Down
Loading