diff --git a/benchmarks/arbitrum-rpc.yml b/benchmarks/arbitrum-rpc.yml index c74501ab4..0f88fadec 100644 --- a/benchmarks/arbitrum-rpc.yml +++ b/benchmarks/arbitrum-rpc.yml @@ -393,6 +393,30 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="arbitrum-official", chain="arbitrum", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="arbitrum-official", chain="arbitrum", region="sgp"}[1h]) + - slug: blockvectra + name: BlockVectra + endpoint: https://api.blockvectra.com/v1/arb_mainnet/public + tag: BlockVectra keyless public Arbitrum One endpoint (3 req/s per IP, 1,000-block history window) + formula: "50th percentile over 24h of client-side round-trip latency (ms) for a single `eth_getBlockByNumber(\"latest\", false)` POST sent every 60s from 3 regions (us-east + eu-west + sgp) to BlockVectra's no-key Arbitrum One endpoint." + queries: + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="arbitrum"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="blockvectra", chain="arbitrum"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="blockvectra", chain="arbitrum"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="blockvectra", chain="arbitrum"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="blockvectra", chain="arbitrum"}) / sum(ocb:rpc_call:rate_24h{provider="blockvectra", chain="arbitrum"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="blockvectra", chain="arbitrum"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="arbitrum"}[1h])) + regions: + - region: us-east + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="arbitrum", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="arbitrum", region="us-east"}[1h]) + - region: eu-west + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="arbitrum", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="arbitrum", region="eu-west"}[1h]) + - region: ap-southeast + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="arbitrum", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="arbitrum", region="sgp"}[1h]) + # API-key cohort (tier: keyed). Queries pin tier="keyed", the label the # rpc-keyed-latency harness emits; the public rows above carry no tier label. - slug: alchemy diff --git a/benchmarks/ethereum-rpc.yml b/benchmarks/ethereum-rpc.yml index 5fcd70a9c..9f5aad0ca 100644 --- a/benchmarks/ethereum-rpc.yml +++ b/benchmarks/ethereum-rpc.yml @@ -393,6 +393,30 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="meowrpc", chain="ethereum", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="meowrpc", chain="ethereum", region="sgp"}[1h]) + - slug: blockvectra + name: BlockVectra + endpoint: https://api.blockvectra.com/v1/eth_mainnet/public + tag: BlockVectra keyless public Ethereum endpoint (3 req/s per IP, 1,000-block history window) + formula: "50th percentile over 24h of client-side round-trip latency (ms) for a single `eth_getBlockByNumber(\"latest\", false)` POST sent every 60s from 3 regions (us-east + eu-west + sgp) to BlockVectra's no-key Ethereum endpoint." + queries: + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="ethereum"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="blockvectra", chain="ethereum"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="blockvectra", chain="ethereum"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="blockvectra", chain="ethereum"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="blockvectra", chain="ethereum"}) / sum(ocb:rpc_call:rate_24h{provider="blockvectra", chain="ethereum"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="blockvectra", chain="ethereum"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="ethereum"}[1h])) + regions: + - region: us-east + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="ethereum", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="ethereum", region="us-east"}[1h]) + - region: eu-west + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="ethereum", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="ethereum", region="eu-west"}[1h]) + - region: ap-southeast + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockvectra", chain="ethereum", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockvectra", chain="ethereum", region="sgp"}[1h]) + # API-key cohort (tier: keyed). Queries pin tier="keyed", the label the # rpc-keyed-latency harness emits; the public rows above carry no tier label. - slug: alchemy diff --git a/harnesses/rpc-capabilities/cmd/script/config.go b/harnesses/rpc-capabilities/cmd/script/config.go index e51ef2143..e665bd5dc 100644 --- a/harnesses/rpc-capabilities/cmd/script/config.go +++ b/harnesses/rpc-capabilities/cmd/script/config.go @@ -300,6 +300,7 @@ func chains() []Chain { {Slug: "nodies", Name: "Nodies (POKT)", URL: envDefault("RPC_URL_ETHEREUM_NODIES", "https://eth-pokt.nodies.app")}, {Slug: "bloxroute", Name: "bloXroute", URL: envDefault("RPC_URL_ETHEREUM_BLOXROUTE", "https://eth.rpc.blxrbdn.com")}, {Slug: "nownodes", Name: "NOWNodes", URL: envDefault("RPC_URL_ETHEREUM_NOWNODES", "https://public-eth.nownodes.io")}, + {Slug: "blockvectra", Name: "BlockVectra", URL: envDefault("RPC_URL_ETHEREUM_BLOCKVECTRA", "https://api.blockvectra.com/v1/eth_mainnet/public")}, }, }, // ─── Polygon PoS (3 providers) ────────────────────────────── @@ -331,6 +332,7 @@ func chains() []Chain { {Slug: "tenderly", Name: "Tenderly Gateway", URL: envDefault("RPC_URL_ARBITRUM_TENDERLY", "https://gateway.tenderly.co/public/arbitrum")}, {Slug: "nodies", Name: "Nodies (POKT)", URL: envDefault("RPC_URL_ARBITRUM_NODIES", "https://arb-pokt.nodies.app")}, {Slug: "arbitrum-official", Name: "Arbitrum Official", URL: envDefault("RPC_URL_ARBITRUM_OFFICIAL", "https://arb1.arbitrum.io/rpc")}, + {Slug: "blockvectra", Name: "BlockVectra", URL: envDefault("RPC_URL_ARBITRUM_BLOCKVECTRA", "https://api.blockvectra.com/v1/arb_mainnet/public")}, }, }, // ─── Optimism (6 providers) ───────────────────────────────── diff --git a/src/lib/providers.ts b/src/lib/providers.ts index 35eb0a2f1..3d524f8d7 100644 --- a/src/lib/providers.ts +++ b/src/lib/providers.ts @@ -1031,7 +1031,9 @@ const buildProvidersCached = unstable_cache( // bench-unfiltered-v184. // v61: thirteen chain RPC pages retire, so every provider on them loses // that appearance. Lockstep with bench-unfiltered-v187. - ["providers-v61"], + // v62: BlockVectra gains two appearances, ethereum-rpc and arbitrum-rpc. + // Lockstep with bench-unfiltered-v189. + ["providers-v62"], // 900 s: the provider index feeds products / compare / answers, whose // numbers move slowly, and this revalidate is also the effective ISR // period of those ~500 pages (Next takes the min across a route's caches). diff --git a/src/lib/spec-provider-set.test.ts b/src/lib/spec-provider-set.test.ts index 0a0d6d582..cf981315e 100644 --- a/src/lib/spec-provider-set.test.ts +++ b/src/lib/spec-provider-set.test.ts @@ -53,6 +53,10 @@ describe("the provider set behind the cache keys", () => { const hash = createHash("sha256").update(sets.join("\n")).digest("hex").slice(0, 16); const count = sets.reduce((n, s) => n + s.split(":")[1].split(",").length, 0); + // An ADDITION on 2026-11-07: BlockVectra joins the public cohorts on + // ethereum-rpc and arbitrum-rpc (issue #3573). A provider already on + // the site, two more appearances: v189/v182/v107 and providers-v62. + // // A REMOVAL on 2026-11-06: thirteen chain RPC pages retire (celo, // taiko, kaia, bob, bitlayer, gravity, axelar, hedera, litecoin, // soneium, zircuit, merlin, comdex), every row on them with them. No @@ -181,6 +185,6 @@ describe("the provider set behind the cache keys", () => { "Then set EXPECTED to the hash in this failure, and add the provider", `to PRODUCT_NAMES if it needs a display name. Providers now: ${count}.`, ].join("\n"), - ).toBe("35fc07b8e50a5ad2"); + ).toBe("e0e5b0e42ccb7ee7"); }); }); diff --git a/src/lib/spec.ts b/src/lib/spec.ts index 0de431087..b9deebfc6 100644 --- a/src/lib/spec.ts +++ b/src/lib/spec.ts @@ -981,7 +981,11 @@ const loadBenchmarkUnfilteredCached = unstable_cache( // each, and route into the cohort at 60% and 30%. Trnch has the // lowest baseline, 78.1%, and the second highest trap rate at 90%, // the only row whose score sits above its own coverage. - ["bench-unfiltered-v188", process.env.VERCEL_ENV === "production" ? "prod" : "all"], + // v189: BlockVectra joins the public cohorts on ethereum-rpc and + // arbitrum-rpc (issue #3573), one more public row on each. Cached + // entries hold the old provider set. Moves with all-benchmarks-v182, + // bench-filters-v107 and providers-v62. + ["bench-unfiltered-v189", process.env.VERCEL_ENV === "production" ? "prod" : "all"], { revalidate: 300, tags: ["benchmarks"] }, ); @@ -1345,7 +1349,9 @@ const loadAllBenchmarksCached = unstable_cache( // v180: lockstep with bench-unfiltered-v187 (thirteen chain RPC pages // retired 2026-11-06; a cached catalog would keep linking them). // v181: lockstep with bench-unfiltered-v188 (bench 313 coverage column). - ["all-benchmarks-v181", process.env.VERCEL_ENV === "production" ? "prod" : "all"], + // v182: lockstep with bench-unfiltered-v189 (BlockVectra on Ethereum and + // Arbitrum). + ["all-benchmarks-v182", process.env.VERCEL_ENV === "production" ? "prod" : "all"], { revalidate: 300, tags: ["benchmarks"] }, ); export const loadAllBenchmarks = cache(loadAllBenchmarksCached); @@ -1601,7 +1607,9 @@ const loadBenchmarkFiltered = unstable_cache( // retired, each with region and tier tabs). // v106: lockstep with bench-unfiltered-v188. The coverage panel is // written under both row slugs, so each tier tab carries it. - ["bench-filters-v106", process.env.VERCEL_ENV === "production" ? "prod" : "all"], + // v107: lockstep with bench-unfiltered-v189. The new public rows carry + // region tabs. + ["bench-filters-v107", process.env.VERCEL_ENV === "production" ? "prod" : "all"], { revalidate: 300, tags: ["benchmarks"] } );