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
62 changes: 46 additions & 16 deletions src/components/rpc-chains-leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { RpcHubChain, RpcRegionKey } from "@/lib/rpc-hub-stats";
type SortKey =
| "name"
| "bestP50"
| "bestP90"
| "us-east"
| "eu-west"
| "sgp"
Expand All @@ -35,6 +36,7 @@ const REGION_COLS: { key: RpcRegionKey; label: string }[] = [
function sortValue(r: RpcHubChain, k: SortKey): number | string | null {
if (k === "name") return r.name.toLowerCase();
if (k === "bestP50") return r.best?.p50Ms ?? null;
if (k === "bestP90") return r.bestP90Ms ?? null;
if (k === "providerCount") return r.providerCount;
return r.regions[k]?.p50Ms ?? null;
}
Expand Down Expand Up @@ -118,6 +120,15 @@ export function RpcChainsLeaderboard({ rows }: { rows: RpcHubChain[] }) {
Best overall (3-region avg)
</span>
</ThSort>
<ThSort
active={sortKey === "bestP90"}
dir={sortDir}
onClick={() => setSort("bestP90")}
>
<span title="p90 latency of the same overall-best provider — the slow-tail number users actually feel. Empty when the provider's histogram doesn't have enough samples yet.">
Best p90
</span>
</ThSort>
{REGION_COLS.map((c) => (
<ThSort
key={c.key}
Expand Down Expand Up @@ -149,20 +160,30 @@ export function RpcChainsLeaderboard({ rows }: { rows: RpcHubChain[] }) {
{i + 1}
</Td>
<Td>
<Link
href={`/benchmarks/${r.slug}`}
className="flex items-center gap-2 min-w-0 group"
onClick={(e) => e.stopPropagation()}
>
<ProviderLogo slug={r.chain} name={r.name} size={18} />
<span className="font-medium text-ink truncate group-hover:underline underline-offset-2">
{r.name}
</span>
<ChevronRight
size={14}
className="text-ink-faint shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"
/>
</Link>
<div className="flex items-center gap-2 min-w-0">
<Link
href={`/benchmarks/${r.slug}`}
className="flex items-center gap-2 min-w-0 group"
onClick={(e) => e.stopPropagation()}
>
<ProviderLogo slug={r.chain} name={r.name} size={18} />
<span className="font-medium text-ink truncate group-hover:underline underline-offset-2">
{r.name}
</span>
<ChevronRight
size={14}
className="text-ink-faint shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"
/>
</Link>
<Link
href={`/chains/${r.chain}`}
className="text-[10px] text-ink-faint hover:text-ink underline underline-offset-2 shrink-0"
title={`Open the ${r.name} chain hub (KPI cards + full RPC leaderboard)`}
onClick={(e) => e.stopPropagation()}
>
hub
</Link>
</div>
</Td>
<Td>
{r.best ? (
Expand All @@ -186,6 +207,15 @@ export function RpcChainsLeaderboard({ rows }: { rows: RpcHubChain[] }) {
<span className="text-ink-faint">...</span>
)}
</Td>
<Td mono>
{r.bestP90Ms != null ? (
<span className="tabular-nums text-ink-soft">
{fmtMs(r.bestP90Ms)}
</span>
) : (
<span className="text-ink-faint">-</span>
)}
</Td>
{REGION_COLS.map((c) => {
const b = r.regions[c.key];
return (
Expand Down Expand Up @@ -215,7 +245,7 @@ export function RpcChainsLeaderboard({ rows }: { rows: RpcHubChain[] }) {
mono
tip={
r.unresponsiveCount
? `${r.unresponsiveCount} cohort provider${r.unresponsiveCount > 1 ? "s" : ""} currently unresponsive on ${r.name} (probed, all calls failing). Not counted in best/fastest.`
? `${r.unresponsiveCount} cohort provider${r.unresponsiveCount > 1 ? "s" : ""} currently unresponsive on ${r.name} (probed, all calls failing). Not counted in best/fastest. Providers: ${(r.unresponsive ?? []).map((u) => u.name).join(", ") || "n/a"}`
: undefined
}
>
Expand Down Expand Up @@ -243,7 +273,7 @@ export function RpcChainsLeaderboard({ rows }: { rows: RpcHubChain[] }) {
{filtered.length === 0 && (
<tr>
<td
colSpan={8}
colSpan={9}
className="px-3 py-8 text-center text-[12px] text-ink-faint"
>
No chain matches &ldquo;{q}&rdquo;.
Expand Down
5 changes: 5 additions & 0 deletions src/lib/rpc-hub-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type RpcHubProvider = {
provider: string;
name: string;
p50Ms: number;
p90Ms?: number;
p99Ms?: number;
successPct?: number;
sampleSize?: number;
Expand Down Expand Up @@ -88,6 +89,8 @@ export type RpcHubChain = {
* field: old blobs without it still parse. */
unresponsive?: RpcHubUnresponsiveProvider[];
best: RpcRegionBest | null;
/** p90 of the overall best provider (same row as `best`). Optional so old blobs stay parseable. */
bestP90Ms?: number;
/** Best provider per probe region. */
regions: Partial<Record<RpcRegionKey, RpcRegionBest>>;
/** Full live provider field, sorted fastest first. */
Expand Down Expand Up @@ -265,11 +268,13 @@ async function buildChain(spec: Spec): Promise<RpcHubChain | null> {
}
: {}),
best: { provider: leader.slug, providerName: leader.name, p50Ms: round1(leader.ms.p50) },
bestP90Ms: Number.isFinite(leader.ms.p90) && leader.ms.p90 > 0 ? round1(leader.ms.p90) : undefined,
regions,
providers: rows.map((r) => ({
provider: r.slug,
name: r.name,
p50Ms: round1(r.ms.p50),
p90Ms: Number.isFinite(r.ms.p90) && r.ms.p90 > 0 ? round1(r.ms.p90) : undefined,
p99Ms: Number.isFinite(r.ms.p99) && r.ms.p99 > 0 ? round1(r.ms.p99) : undefined,
successPct:
Number.isFinite(r.successRate) && r.successRate > 0
Expand Down
Loading