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
70 changes: 70 additions & 0 deletions app/scaling/components/GlamsterdamComparison.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { renderToStaticMarkup } from 'react-dom/server';
import { expect, it } from 'vitest';

import { GlamsterdamComparisonSection } from './GlamsterdamComparison';
import type { Run } from '../proven/capacity';

const run = (id: string, mgas: number, tps: number, gps: number, workload: Run['workload'] = 'mix'): Run => ({
id,
outputDir: id,
workload,
mgas,
gps,
tps,
reverted: 0,
passed: true,
commit: 'abc123',
createdAt: 1,
steps: [],
replay: null,
proofNode: null,
da: null,
storage: null,
blockLatency: null,
});

it('shows the benchmark source setup message when jobs are unavailable', () => {
const html = renderToStaticMarkup(<GlamsterdamComparisonSection configured={false} />);
expect(html).toContain('Benchmark source is not configured.');
});

it('shows Glamsterdam and Main jobs side by side without pairing or TPS-gap calculations', () => {
const glamsterdamRuns = [run('glam-mix-200', 200, 2238.2, 204.5e6), run('glam-pay-300', 300, 1520, 302e6, 'payment')];
const mainRuns = [run('main-mix-200', 200, 2970.6, 203e6), run('main-mix-400', 400, 5942.5, 406.5e6)];
const html = renderToStaticMarkup(
<GlamsterdamComparisonSection configured glamsterdamRuns={glamsterdamRuns} mainRuns={mainRuns} />,
);

expect(html).toContain('Glamsterdam jobs');
expect(html).toContain('All Main targets');
expect(html).toContain('All Glamsterdam targets');
expect(html).toContain('Latest Glamsterdam mix run');
expect(html).toContain('Latest Main mix run');
expect(html).toContain('glam-mix-200');
expect(html).toContain('glam-pay-300');
expect(html).toContain('main-mix-200');
expect(html).toContain('main-mix-400');
expect(html).toContain('2,238.2');
expect(html).toContain('2,970.6');
expect(html).toContain('5,942.5');
expect(html).toContain('Actual Mgas/s');
expect(html).toContain('Successful TPS');
expect(html).not.toContain('closest TPS');
expect(html).not.toContain('TPS gap');
});

/** Verifies highlights select by recency, exclude non-mix runs, and retain the inventory. */
it('highlights the latest mix run rather than the largest target or newest other workload', () => {
const older = { ...run('older-high-target', 400, 5000, 406e6), createdAt: 1 };
const newest = { ...run('newest-mix', 100, 1200, 102e6), createdAt: 3, reverted: 0.25 };
const payment = { ...run('newest-payment', 300, 2000, 302e6, 'payment'), createdAt: 4 };
const html = renderToStaticMarkup(<GlamsterdamComparisonSection configured glamsterdamRuns={[older, payment, newest]} mainRuns={[]} />);
const cards = html.slice(0, html.indexOf('All Glamsterdam targets'));
expect(cards, 'latest mix card uses the newest mix job link').toContain('href="/scaling/runs/bench/newest-mix"');
expect(cards, 'largest target is not assumed newest').not.toContain('older-high-target');
expect(cards, 'newer payment does not replace latest mix').not.toContain('newest-payment');
expect(cards, 'successful TPS excludes 25% reverted').toContain('900 successful TPS');
expect(cards, 'empty Main has an explicit empty state').toContain('No eligible mix jobs in the last 14 days.');
expect(html, 'older mix remains in the full inventory').toContain('older-high-target');
expect(html, 'payment remains in the full inventory').toContain('newest-payment');
});
135 changes: 135 additions & 0 deletions app/scaling/components/GlamsterdamComparison.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { Text } from '../../components/ui/Text';
import { DA_WORKLOADS } from '../da/workloads';
import { runHref, successfulTps, type Run } from '../proven/capacity';

type Props = {
configured: boolean;
glamsterdamRuns?: Run[];
mainRuns?: Run[];
glamsterdamErrors?: number;
error?: unknown;
};

const TH = 'px-3 py-2 text-left font-[600] text-bds-gray-60';
const TD = 'border-t border-bds-gray-10 px-3 py-2 align-top dark:border-white/10';
const tps = (run: Run) => successfulTps(run).toLocaleString('en-US', { maximumFractionDigits: 1 });
const rate = (run: Run) => (run.gps / 1e6).toLocaleString('en-US', { maximumFractionDigits: 1 });

/** Highlights the newest eligible mix run without matching it to the other branch. */
function LatestRun({ title, runs, accent = false }: { title: string; runs: Run[]; accent?: boolean }) {
const latest = runs.filter((run) => run.workload === 'mix').reduce<Run | undefined>(
(newest, run) => !newest || run.createdAt > newest.createdAt ? run : newest, undefined,
);
return (
<div className="min-w-0 rounded-lg border border-bds-gray-10 p-5 dark:border-white/10">
<h3 className="text-[10px] uppercase tracking-[0.09em] text-bds-gray-60">{title}</h3>
{latest ? (
<>
<div className="my-2 flex flex-wrap items-baseline gap-x-2 tabular-nums">
<span className={`text-[32px] leading-tight tracking-[-1px] ${accent ? 'text-brand-blue' : ''}`}>{rate(latest)}</span>
<span className="text-xs text-bds-gray-60">Mgas/s actual</span>
</div>
<p className="text-xs leading-relaxed text-bds-gray-60">
Target {latest.mgas.toLocaleString('en-US')} Mgas/s · {tps(latest)} successful TPS ·{' '}
<a className="text-brand-blue underline underline-offset-4" href={runHref(latest)}>View job ↗</a>
</p>
</>
) : <Text variant="label.regular" tone="muted">No eligible mix jobs in the last 14 days.</Text>}
</div>
);
}

/** Lists independent measured runs across all workloads and targets. */
function RunTable({ title, runs }: { title: string; runs: Run[] }) {
return (
<div className="flex min-w-0 flex-col gap-2">
<Text as="h3" variant="label.regular">
{title}
</Text>
{runs.length === 0 ? (
<Text variant="label.regular" tone="muted">No eligible jobs in the last 14 days.</Text>
) : (
<div className="overflow-x-auto rounded-lg border border-bds-gray-10 dark:border-white/10">
<table className="w-full min-w-[480px] border-collapse text-[13px]">
<thead>
<tr className="border-b border-bds-gray-10 dark:border-white/10">
<th className={TH}>Workload</th>
<th className={TH}>Target</th>
<th className={TH}>Job</th>
<th className={TH}>Actual Mgas/s</th>
<th className={TH}>Successful TPS</th>
</tr>
</thead>
<tbody>
{runs.map((run) => {
const workload = DA_WORKLOADS.find((item) => item.payload === run.workload)?.label ?? run.workload;
return (
<tr key={run.outputDir}>
<td className={TD}>{workload}</td>
<td className={`${TD} whitespace-nowrap tabular-nums`}>{run.mgas.toLocaleString('en-US')} Mgas/s</td>
<td className={TD}>
<a className="break-all underline" href={runHref(run)}>
{run.id}
</a>
</td>
<td className={`${TD} whitespace-nowrap tabular-nums`}>{rate(run)}</td>
<td className={`${TD} whitespace-nowrap tabular-nums`}>{tps(run)}</td>
</tr>
);
})}
</tbody>
</table>
</div>
)}
</div>
);
}

/** Shows latest mix results above separate Glamsterdam and Main run inventories. */
export function GlamsterdamComparisonSection({
configured,
glamsterdamRuns,
mainRuns,
glamsterdamErrors = 0,
error,
}: Props) {
const message = !configured
? 'Benchmark source is not configured.'
: error
? 'Could not load benchmark data.'
: !glamsterdamRuns || !mainRuns
? 'Loading benchmark runs…'
: null;

return (
<section aria-label="Glamsterdam jobs" className="flex flex-col gap-3">
<Text as="h2" variant="headline">
Glamsterdam
</Text>
<Text variant="label.regular" tone="muted">
Latest run per workload and target in the last 14 days. TPS excludes reverted transactions; gas throughput is measured.
</Text>
{message ? (
<Text variant="label.regular" tone="muted">
{message}
</Text>
) : (
<>
{glamsterdamErrors > 0 ? (
<Text variant="label.regular" tone="muted">
{glamsterdamErrors} latest Glamsterdam job{glamsterdamErrors === 1 ? '' : 's'} could not be loaded.
</Text>
) : null}
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<LatestRun title="Latest Glamsterdam mix run" runs={glamsterdamRuns!} accent />
<LatestRun title="Latest Main mix run" runs={mainRuns!} />
</div>
<div className="mt-3 grid grid-cols-1 gap-6 border-t border-bds-gray-10 pt-6 dark:border-white/10 xl:grid-cols-2">
<RunTable title="All Glamsterdam targets" runs={glamsterdamRuns!} />
<RunTable title="All Main targets" runs={mainRuns!} />
</div>
</>
)}
</section>
);
}
2 changes: 2 additions & 0 deletions app/scaling/components/Scorecard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Ladder, type ProvenMark } from './Ladder';
import { day, useProvenCapacity } from './ProvenCapacity';
import { Work } from './Work';
import { subsystemCards, WorkloadSubsystems } from './WorkloadSubsystems';
import { GlamsterdamComparisonSection } from './GlamsterdamComparison';

function benchMark({ mgas, atTop, run }: Proven): ProvenMark {
const top = atTop ? ` ≥ because ${mgas} Mgas/s is the highest rate the bench runs.` : '';
Expand Down Expand Up @@ -51,6 +52,7 @@ export function Scorecard({ snapshot, benchUrl }: { snapshot: Snapshot; benchUrl
<Ladder ladder={ladder} windows={snapshot.windows} proven={mark} max={max} limits={limits} />
<Bottlenecks limits={limits} max={max} gasLimit={ladder.configuredLimit.value} proven={proven} history={data?.history ?? []} mainnetGasPerTx={mainnetGasPerTx(snapshot)} />
<WorkloadSubsystems cards={subsystemCards(data, limits, snapshot, ladder.configuredLimit.value)} />
<GlamsterdamComparisonSection configured={!!benchUrl} glamsterdamRuns={data?.glamsterdamRuns} mainRuns={data?.mainRuns} glamsterdamErrors={data?.glamsterdamErrors ?? 0} error={bench.error} />
<Work work={snapshot.work} />
</>
);
Expand Down
41 changes: 39 additions & 2 deletions app/scaling/components/scorecard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ const storage = (currentBytes: number | null = null): NonNullable<Run['storage']
const bench = (mgas: number, atTop: boolean, more: Partial<ProvenCapacity> = {}): ProvenCapacity => ({
current: { ...none, mix: { mgas, atTop, run: run(mgas) } },
da: none,
glamsterdamRuns: [],
mainRuns: [],
glamsterdamErrors: 0,
history: [
{ at: T0, mgas: 40, commit: 'aaaaaaaaaaaaaaaa', previousCommit: null, compareUrl: null },
{ at: T0 + 5 * DAY, mgas, commit: 'bbbbbbbbbbbbbbbb', previousCommit: 'aaaaaaaaaaaaaaaa', compareUrl: 'https://github.com/base/base/compare/aaaa...bbbb' },
Expand All @@ -66,8 +69,8 @@ const fixture = (): Snapshot => JSON.parse(readFileSync(new URL('../fixtures/syn
// In page order: the freshness line, then headline, ladder, ranked limits, workloads, work.
const render = (props: { benchUrl?: string } = { benchUrl: BENCH }, snapshot = fixture()) => {
const html = renderToStaticMarkup(<Scorecard snapshot={snapshot} {...props} />);
const [fresh, head, ladder, ranked, subsystems, work] = html.split('<section');
return { html, fresh, head, ladder, ranked, subsystems, work };
const [fresh, head, ladder, ranked, subsystems, glamsterdam, work] = html.split('<section');
return { html, fresh, head, ladder, ranked, subsystems, glamsterdam, work };
};
// Strip tags until none remain, so a tag split across a removed one cannot survive.
const text = (html: string) => {
Expand Down Expand Up @@ -124,6 +127,40 @@ describe('freshness and headline', () => {

});

describe('Glamsterdam jobs', () => {
it('shows Glamsterdam and Main jobs side by side with measured rates and run links', () => {
const main = { ...run(400), id: 'main-mix-400', outputDir: 'main-mix-400', tps: 2200.24 };
const glamsterdam = { ...run(200), id: 'glam-mix-200', outputDir: 'glam-mix-200', gps: 197e6, tps: 2100.14 };
swr.result = { data: bench(400, true, { mainRuns: [main], glamsterdamRuns: [glamsterdam] }) };
const section = render().glamsterdam;

expect(text(section)).toContain('All Glamsterdam targets');
expect(text(section)).toContain('All Main targets');
expect(text(section)).toContain('glam-mix-200');
expect(text(section)).toContain('main-mix-400');
expect(text(section)).toContain('2,100.1');
expect(text(section)).toContain('2,200.2');
expect(section).toContain('href="/scaling/runs/bench/glam-mix-200"');
expect(section).toContain('href="/scaling/runs/bench/main-mix-400"');
expect(section).not.toContain('closest TPS');
expect(section).not.toContain('TPS gap');
});

it('distinguishes unconfigured, loading, error and unavailable jobs', () => {
expect(text(render({}).glamsterdam)).toContain('Benchmark source is not configured.');
expect(text(render().glamsterdam)).toContain('Loading benchmark runs…');

swr.result = { error: new Error('offline') };
expect(text(render().glamsterdam)).toContain('Could not load benchmark data.');

swr.result = { data: bench(400, true) };
expect(text(render().glamsterdam)).toContain('No eligible jobs in the last 14 days.');
swr.result = { data: bench(400, true, { glamsterdamErrors: 1 }) };
expect(text(render().glamsterdam)).toContain('1 latest Glamsterdam job could not be loaded.');
});
});


describe('workload tiles', () => {
it('takes the lowest of the proven, DA and gas-limit ceilings, preferring DA then the gas limit on ties', () => {
expect(sustainable(400, 82, 200)).toEqual({ mgas: 82, cap: 'DA' });
Expand Down
3 changes: 2 additions & 1 deletion app/scaling/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const area = async (id: string) => renderToStaticMarkup(await ScalingAreaPage({
it('ends the first screen with the DA link, and no guardrails or benchmark links', async () => {
const html = renderToStaticMarkup(await ScalingPage());
expect(html).toContain('<a class="underline" href="/scaling/da">DA by workload</a>');
expect(html).toContain('Block Gas Limit: 40 Mgas');
// The guardrails page stays, unlinked, while the first screen leaves guardrails out.
expect(html).not.toMatch(/href="\/scaling\/guardrails"|Guardrails<\/h2>|SLOs/);
expect(html).not.toMatch(/href="\/benchmark|href="\/scaling\/networking"/);
Expand All @@ -33,7 +34,7 @@ it('ends the first screen with the DA link, and no guardrails or benchmark links

it('orders the first screen: freshness, headline, ladder, ranked limits, subsystems by workload, work, links', async () => {
const html = renderToStaticMarkup(await ScalingPage());
const order = ['Usage to 2026-01-02', 'Proven capacity', 'How close are we, and to what?', 'What breaks first', 'Subsystems by workload', 'Work log', 'DA by workload'].map((h) => html.indexOf(h));
const order = ['Block Gas Limit: 40 Mgas', 'Usage to 2026-01-02', 'Proven capacity', 'How close are we, and to what?', 'What breaks first', 'Subsystems by workload', 'Glamsterdam', 'Work log', 'DA by workload'].map((h) => html.indexOf(h));
expect(order.every((i, k) => i > (order[k - 1] ?? -1))).toBe(true);
expect(html).not.toMatch(/Subsystem detail|>Progress<|Ceilings by bottleneck|Usage data as of/);
});
Expand Down
10 changes: 9 additions & 1 deletion app/scaling/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { Header, loadSnapshot, Unavailable } from './loadSnapshot';
// The snapshot is a runtime file, so render per request rather than at build.
export const dynamic = 'force-dynamic';

// Convert the configured Mgas/s rate to gas per 200ms block.
const BASE_BLOCK_TIME_SECONDS = 0.2;

export default async function ScalingPage() {
const loaded = await loadSnapshot();
if (loaded.kind !== 'ok') return <Unavailable loaded={loaded} />;
Expand All @@ -17,7 +20,12 @@ export default async function ScalingPage() {
const dashboardUrl = process.env.SCALING_DATADOG_DASHBOARD_URL;
return (
<div className="flex flex-col gap-10 pb-8">
<Header title={`${snapshot.network} capacity`} />
<div className="flex flex-col gap-1.5">
<Header title={`${snapshot.network} capacity`} />
<Text variant="label.regular" tone="muted">
Block Gas Limit: {snapshot.ladder.configuredLimit.value === null ? '—' : `${(snapshot.ladder.configuredLimit.value * BASE_BLOCK_TIME_SECONDS).toLocaleString('en-US', { maximumFractionDigits: 1 })} Mgas`}
</Text>
</div>
<Scorecard snapshot={snapshot} benchUrl={process.env.SCALING_BENCH_BASE_URL} />
<Text variant="label.regular" tone="muted">
<span className="flex flex-wrap gap-x-4">
Expand Down
Loading
Loading