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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ jobs:
/internal-explorer/bundles/0x1 /api/internal-explorer/blocks \
/tips /tips/block/0x1 /tips/bundles/0x1 /api/tips/blocks \
/benchmark /benchmark/run/latest /benchmark/run-comparison/1 \
/benchmark/load-tests/sepolia /scaling /scaling/da /scaling/guardrails; do
/benchmark/load-tests/sepolia /scaling /scaling/da /scaling/guardrails /scaling/runs; do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:3000${route}")
if [ "${code}" != "404" ]; then
echo "FAIL: ${route} returned ${code}, expected 404"
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/BaseChart.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useRef, useEffect, useState } from "react";
import * as d3 from "d3";
import { MetricData } from "../types";
import { MetricData } from "../../scaling/runs/lib/types";

interface BaseChartProps {
data: MetricData[];
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/BenchmarkToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useRouter, useSearchParams } from "next/navigation";

import { useLoadTestList, useTestMetadata } from "../utils/useDataSeries";
import { uniqBy } from "../utils/collections";
import { formatLoadTestTimestamp } from "../utils/formatters";
import { formatLoadTestTimestamp } from "../../scaling/runs/lib/formatters";
import { loadTestHref } from "../routes";
import Select from "./Select";

Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ChartGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { SORTED_CHART_CONFIG } from "../metricDefinitions";
import { DataSeries } from "../types";
import { SORTED_CHART_CONFIG } from "../../scaling/runs/lib/metricDefinitions";
import { DataSeries } from "../../scaling/runs/lib/types";
import LineChart from "./LineChart";

interface ProvidedProps {
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ChartSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import { useEffect, useMemo, useRef } from "react";
import { BenchmarkRuns } from "../types";
import { BenchmarkRuns } from "../../scaling/runs/lib/types";
import { deepEqual } from "../utils/collections";
import {
camelToTitleCase,
formatValue,
formatLabel,
} from "../utils/formatters";
} from "../../scaling/runs/lib/formatters";
import { interpolateWarm } from "d3";
import { useBenchmarkFilters } from "../hooks/useBenchmarkFilters";
import Link from "next/link";
Expand Down
5 changes: 3 additions & 2 deletions app/benchmark/components/ConfigCard.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { describe, expect, it } from "vitest";

import { buildRows, formatTransactions } from "./ConfigCard";
import { LoadTestConfig } from "../types";
import { buildRows } from "./ConfigCard";
import { formatTransactions } from "../../scaling/runs/lib/formatters";
import { LoadTestConfig } from "../../scaling/runs/lib/types";

describe("formatTransactions", () => {
it("formats a weighted transaction mix", () => {
Expand Down
28 changes: 2 additions & 26 deletions app/benchmark/components/ConfigCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LoadTestConfig } from "../types";
import { formatEthFromWeiString } from "../utils/formatters";
import { LoadTestConfig } from "../../scaling/runs/lib/types";
import { formatEthFromWeiString, formatTransactions } from "../../scaling/runs/lib/formatters";
import StatCard from "./StatCard";

interface ConfigCardProps {
Expand All @@ -11,30 +11,6 @@ interface Row {
value: string;
}

const percent = (value: number): string => `${Math.round(value * 100)}%`;

export const formatTransactions = (
config: Pick<LoadTestConfig, "transactions" | "fresh_recipient_ratio">,
): string => {
const txs = config.transactions;
if (!txs || txs.length === 0) return "—";
const total = txs.reduce((acc, t) => acc + t.weight, 0);
if (total === 0) return txs.map((t) => t.type).join(" · ");

const freshRecipientRatio = config.fresh_recipient_ratio ?? 0;
return txs
.map((t) => {
if (t.type === "transfer" && freshRecipientRatio >= 1) {
return `account-create (${percent(t.weight / total)})`;
}
if (t.type === "transfer" && freshRecipientRatio > 0) {
return `${t.type} (${percent(t.weight / total)}, ${percent(freshRecipientRatio)} account-create)`;
}
return `${t.type} (${percent(t.weight / total)})`;
})
.join(" · ");
};

const formatTargetGps = (gps: number): string => {
if (gps >= 1e9) return `${(gps / 1e9).toFixed(1)}B gas/s`;
if (gps >= 1e6) return `${(gps / 1e6).toFixed(0)}M gas/s`;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ConfigurationTags.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { formatValue, formatLabel } from "../utils/formatters";
import { camelToTitleCase } from "../utils/formatters";
import { formatValue, formatLabel } from "../../scaling/runs/lib/formatters";
import { camelToTitleCase } from "../../scaling/runs/lib/formatters";

interface ConfigurationTagsProps {
testConfig: Record<string, unknown>;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import React, {
useMemo,
} from "react";
import * as d3 from "d3";
import { DataSeries, MetricData, ChartConfig } from "../types";
import { DataSeries, MetricData, ChartConfig } from "../../scaling/runs/lib/types";
import BaseChart from "./BaseChart";
import { formatValue, formatLabel } from "../utils/formatters";
import { formatValue, formatLabel } from "../../scaling/runs/lib/formatters";
import calculateTooltipLayout from "../hooks/useTooltipLayout";
import useChartHoverSync, { ChartHoverEvent } from "../hooks/useChartHoverSync";
import { deepEqual } from "../utils/collections";
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/MachineInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MachineInfo as MachineInfoType } from "../types";
import { MachineInfo as MachineInfoType } from "../../scaling/runs/lib/types";

interface MachineInfoProps {
machineInfo?: MachineInfoType;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/RunList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { groupBy } from "../utils/collections";
import { useState } from "react";
import { formatValue, MetricValue } from "../utils/formatters";
import { formatValue, MetricValue } from "../../scaling/runs/lib/formatters";
import ThresholdDisplay from "../views/ThresholdDisplay";
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";
import StatusBadge from "./StatusBadge";
import StatusSummary from "./StatusSummary";
import ConfigurationTags from "./ConfigurationTags";
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/RunListFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import Link from "next/link";
import { useState } from "react";
import { camelToTitleCase, formatLabel } from "../utils/formatters";
import { camelToTitleCase, formatLabel } from "../../scaling/runs/lib/formatters";
import { FilterValue } from "../filter";
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";
import { downloadAllRuns, downloadAllRunsCSV } from "../utils/downloadUtils";
import Select from "./Select";
import FloatingDropdown from "./FloatingDropdown";
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ThroughputChart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from "react";
import * as d3 from "d3";
import { ThroughputSample } from "../types";
import { formatTps, formatGps } from "../utils/formatters";
import { ThroughputSample } from "../../scaling/runs/lib/types";
import { formatTps, formatGps } from "../../scaling/runs/lib/formatters";

interface ThroughputChartProps {
samples: ThroughputSample[];
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/filter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from "vitest";
import { getBenchmarkVariables } from "./filter";
import { BenchmarkRun } from "./types";
import { BenchmarkRun } from "../scaling/runs/lib/types";

// Sample data for testing - This data now aligns with the ActualBenchmarkRun type
const sampleRuns: BenchmarkRun[] = [
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/hooks/useBenchmarkFilters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react";
import { deepEqual } from "../utils/collections";
import { type BenchmarkRun } from "../types";
import { type BenchmarkRun } from "../../scaling/runs/lib/types";
import { useSearchParamsState } from "../utils/useSearchParamsState";
import { getBenchmarkVariables } from "../filter";
type FilterValue = string | number | boolean;
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/utils/downloadUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";

/**
* Downloads run information as a JSON file
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/utils/useDataSeries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
LoadTestEntry,
LoadTestResult,
MetricData,
} from "../types";
} from "../../scaling/runs/lib/types";
import { useCallback } from "react";
import { getDataService } from "../services/dataService";
import { getDataService } from "../../scaling/runs/lib/dataService";

// Fetch metrics data using the configured data service
export const fetchMetrics = async (
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/LoadTestAllRuns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Link from "next/link";
import { useLoadTestList } from "../utils/useDataSeries";
import { formatLoadTestTimestamp } from "../utils/formatters";
import { formatLoadTestTimestamp } from "../../scaling/runs/lib/formatters";
import { loadTestHref, loadTestsHref } from "../routes";

interface ProvidedProps {
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/views/LoadTestDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import {
formatGpsVerbose,
formatLoadTestTimestamp,
formatTps,
} from "../utils/formatters";
} from "../../scaling/runs/lib/formatters";
import {
BlockRange,
FlashblocksLatencyStats,
LatencyStats,
LoadTestResult,
} from "../types";
} from "../../scaling/runs/lib/types";
import { LoadTestRunSelect } from "../components/BenchmarkToolbar";
import { loadTestAllHref } from "../routes";

Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/RunComparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ChartSelector, {
} from "../components/ChartSelector";
import ChartGrid from "../components/ChartGrid";
import { useTestMetadata, useMultipleDataSeries } from "../utils/useDataSeries";
import { DataSeries } from "../types";
import { DataSeries } from "../../scaling/runs/lib/types";
import { BenchmarkRunSelect } from "../components/BenchmarkToolbar";
import DataSourceError from "../components/DataSourceError";
import { runComparisonHref } from "../routes";
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/RunIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTestMetadata } from "../utils/useDataSeries";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { getBenchmarkVariables } from "../filter";
import RunList from "../components/RunList";
import { BenchmarkRuns, getTestRunsWithStatus } from "../types";
import { BenchmarkRuns, getTestRunsWithStatus } from "../../scaling/runs/lib/types";
import { groupBy } from "../utils/collections";
import RunListFilter from "../components/RunListFilter";
import { BenchmarkRunSelect } from "../components/BenchmarkToolbar";
Expand Down
3 changes: 2 additions & 1 deletion app/scaling/loadSnapshot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ export function Unavailable({ loaded }: { loaded: Exclude<Loaded, { kind: 'ok' }
);
}

export function Header({ loaded, title, crumb }: { loaded: Extract<Loaded, { kind: 'ok' }>; title: ReactNode; crumb?: string }) {
export function Header({ loaded, title, crumb, action }: { loaded: Extract<Loaded, { kind: 'ok' }>; title: ReactNode; crumb?: string; action?: ReactNode }) {
const { snapshot, ageDays, stale } = loaded;
return (
<header className="flex flex-col gap-3">
{crumb ? (
<Text variant="label.regular" tone="muted"><Link className="underline" href="/scaling">Scaling</Link> / {crumb}</Text>
) : null}
<Text as="h1" variant="title2">{title}</Text>
{action}
<Text variant="label.regular" tone="muted">
As of {formatTime(snapshot.collectedAt)} ({ageDays === 0 ? 'today' : `${ageDays}d old`}) · manually refreshed
snapshot, not live data. {snapshot.context}
Expand Down
1 change: 1 addition & 0 deletions app/scaling/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ it('links the first screen to five detail pages instead of listing metric rows',
const html = renderToStaticMarkup(await ScalingPage());
for (const page of ['da', 'execution', 'state', 'networking', 'guardrails']) expect(html).toContain(`href="/scaling/${page}"`);
expect(html).not.toContain('Blob utilization');
expect(html).toContain('href="/scaling/runs"');
});

it('shows every metric row on its detail page', async () => {
Expand Down
2 changes: 1 addition & 1 deletion app/scaling/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function ScalingPage() {
const { snapshot } = loaded;
return (
<div className="flex flex-col gap-10 pb-8">
<Header loaded={loaded} title={`Scaling scorecard · ${snapshot.network}`} />
<Header loaded={loaded} title={`Scaling scorecard · ${snapshot.network}`} action={<Link className="underline" href="/scaling/runs">Runs →</Link>} />

<Ladder ladder={snapshot.ladder} ceilings={snapshot.ceilings} translations={snapshot.translations} windows={snapshot.windows} />
<CeilingCards ceilings={snapshot.ceilings} />
Expand Down
70 changes: 70 additions & 0 deletions app/scaling/runs/fixtures/synthetic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"metadata": {
"runs": [
{
"id": "test-synthetic-1",
"sourceFile": "synthetic.yml",
"testName": "Synthetic bench run",
"testDescription": "Invented values for tests.",
"outputDir": "synthetic-1",
"createdAt": "2026-01-07T12:00:00Z",
"testConfig": { "BenchmarkRun": "test-synthetic-1", "BlockTimeMilliseconds": 1000, "GasLimit": 100000000, "TransactionPayload": "synthetic-payload" },
"machineInfo": { "type": "synthetic.large", "provider": "", "region": "", "fileSystem": "ext4" },
"thresholds": { "warning": { "latency/get_payload": 50000000 } },
"result": {
"success": true,
"complete": true,
"sequencerMetrics": { "gasPerSecond": 42000000, "forkChoiceUpdated": 0.001, "getPayload": 0.02, "sendTxs": 0.01 },
"validatorMetrics": { "gasPerSecond": 420000000, "newPayload": 0.03 }
}
},
{
"id": "test-synthetic-2",
"sourceFile": "synthetic.yml",
"testName": "Synthetic incomplete run",
"testDescription": "Invented values for tests.",
"outputDir": "synthetic-2",
"createdAt": "2025-12-20T12:00:00Z",
"testConfig": { "BenchmarkRun": "test-synthetic-2" },
"result": null
}
]
},
"loadTests": [
{
"network": "sepolia",
"timestamp": "2026-01-08T00-00-01",
"result": {
"block_latency": { "min": { "secs": 1, "nanos": 0 }, "max": { "secs": 3, "nanos": 0 }, "mean": { "secs": 2, "nanos": 0 }, "p50": { "secs": 2, "nanos": 0 }, "p95": { "secs": 2, "nanos": 500000000 }, "p99": { "secs": 3, "nanos": 0 } },
"flashblocks_latency": { "count": 10, "min": { "secs": 0, "nanos": 100000000 }, "max": { "secs": 0, "nanos": 900000000 }, "mean": { "secs": 0, "nanos": 300000000 }, "p50": { "secs": 0, "nanos": 250000000 }, "p90": { "secs": 0, "nanos": 600000000 }, "p95": { "secs": 0, "nanos": 700000000 }, "p99": { "secs": 0, "nanos": 800000000 } },
"throughput": { "total_submitted": 1000, "total_confirmed": 990, "total_failed": 10, "total_reverted": 0, "tps": 33, "gps": 12500000, "duration": { "secs": 30, "nanos": 0 } },
"throughput_percentiles": { "tps_p50": 30, "tps_p90": 35, "tps_p99": 36, "tps_max": 36, "gps_p50": 12000000, "gps_p90": 13000000, "gps_p99": 13500000, "gps_max": 13500000 },
"gas": { "total_gas": 375000000, "avg_gas": 378787, "total_cost_wei": 1000000000000, "avg_gas_price": 1000 },
"top_failure_reasons": [],
"config": {
"funding_amount": "1000000000000000000", "sender_count": 10, "sender_offset": 0, "in_flight_per_sender": 4,
"duration": "30s", "target_gps": 15000000, "seed": 1, "chain_id": null,
"transactions": [{ "type": "transfer", "weight": 3 }, { "type": "swap", "weight": 1 }],
"looper_contract": null, "swap_token_amount": "0"
}
}
},
{
"network": "sepolia",
"timestamp": "2026-01-01-00-00-02",
"result": {
"block_latency": { "min": { "secs": 1, "nanos": 0 }, "max": { "secs": 2, "nanos": 0 }, "mean": { "secs": 1, "nanos": 500000000 }, "p50": { "secs": 1, "nanos": 500000000 }, "p95": { "secs": 1, "nanos": 900000000 }, "p99": { "secs": 2, "nanos": 0 } },
"flashblocks_latency": { "count": 5, "min": { "secs": 0, "nanos": 100000000 }, "max": { "secs": 0, "nanos": 500000000 }, "mean": { "secs": 0, "nanos": 200000000 }, "p50": { "secs": 0, "nanos": 200000000 }, "p90": { "secs": 0, "nanos": 400000000 }, "p95": { "secs": 0, "nanos": 450000000 }, "p99": { "secs": 0, "nanos": 500000000 } },
"throughput": { "total_submitted": 500, "total_confirmed": 500, "total_failed": 0, "total_reverted": 0, "tps": 17, "gps": 6000000, "duration": { "secs": 30, "nanos": 0 } },
"throughput_percentiles": { "tps_p50": 16, "tps_p90": 18, "tps_p99": 18, "tps_max": 18, "gps_p50": 6000000, "gps_p90": 6500000, "gps_p99": 6500000, "gps_max": 6500000 },
"gas": { "total_gas": 180000000, "avg_gas": 360000, "total_cost_wei": 1000000000000, "avg_gas_price": 1000 },
"top_failure_reasons": []
}
},
{
"network": "sepolia",
"timestamp": "2025-12-31T00-00-03",
"result": { "error": "synthetic fatal error" }
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
LoadTestEntry,
LoadTestResult,
MetricData,
} from "../types";
} from "./types";

// Load-test endpoints live under the versioned API prefix, unlike benchmark
// data which uses the legacy unversioned `output/` paths. Centralized here so
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChartConfig, RustDuration } from "../types";
import { ChartConfig, LoadTestConfig, RustDuration } from "./types";

const PREFIXES = {
"": 1,
Expand Down Expand Up @@ -227,3 +227,27 @@ export const camelToTitleCase = (str: string) => {
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
};

const percent = (value: number): string => `${Math.round(value * 100)}%`;

export const formatTransactions = (
config: Pick<LoadTestConfig, "transactions" | "fresh_recipient_ratio">,
): string => {
const txs = config.transactions;
if (!txs || txs.length === 0) return "—";
const total = txs.reduce((acc, t) => acc + t.weight, 0);
if (total === 0) return txs.map((t) => t.type).join(" · ");

const freshRecipientRatio = config.fresh_recipient_ratio ?? 0;
return txs
.map((t) => {
if (t.type === "transfer" && freshRecipientRatio >= 1) {
return `account-create (${percent(t.weight / total)})`;
}
if (t.type === "transfer" && freshRecipientRatio > 0) {
return `${t.type} (${percent(t.weight / total)}, ${percent(freshRecipientRatio)} account-create)`;
}
return `${t.type} (${percent(t.weight / total)})`;
})
.join(" · ");
};
File renamed without changes.
Loading
Loading