Files
zeekay 87aa0fa367 chains: read each chain from that chain, and list the ones this network runs
/chains showed fifteen rows on every network, from a hardcoded table. Four of
them — T, R, I, O — are registered on no network at all; the node answers
"there is no ID with alias: T". A fifth, M, runs on devnet alone. And every
/chains/<slug> page printed the same four numbers: the primary network's
validator count, its total stake, its chain count, its threshold. Nothing on
Q-Chain's page was about Q-Chain. Fifteen pages, one set of facts.

The network already knows its own answer. platform.getBlockchains is the chain
list, and it is per-network for free: mainnet and testnet report nine chains,
devnet reports ten including M. That is what /chains lists now, joined with
configs/app/primaryChains.ts for presentation only — a chain the network
reports and we have no metadata for still gets a row, because the network is
the source of truth and our table is not.

Three facts per chain, each read from that chain:

  * the blockchain ID, from the registry — the thing that actually tells one
    chain from another, and it was already on screen while the numbers above
    it were not
  * whether the node has bootstrapped it, from info.isBootstrapped, which the
    gateway routes for every chain. This is how Q-Chain's page now says
    Syncing where the other nine say Bootstrapped: Q has not come up on any of
    the three networks and is the sole reason all three report healthy:false
  * its head, in its own dialect — eth_blockNumber for C, platform.getHeight
    for P, xvm.getHeight for X. Not avm: that service is gone from this build,
    and asking it returns "can't find service" rather than a height

Validators are the P-Chain's model, so they render on the P-Chain and nowhere
else. The head is labelled for the model it comes from — the X-Chain's is an
accepted height, not a block height.

Where a chain has no head to read, it says so. The gateway routes exactly P, X
and C on all three networks; D, A, B, Z, G, K and Q are registered and
bootstrapped on the node but their RPC 404s from a browser. Proof it is the
route and not the chain: C-Chain's own blockchain ID, /v1/bc/25td8att…/rpc,
404s while /v1/bc/C/rpc returns a height — same chain, same node. Those pages
read "No public RPC" and say plainly that the chain is registered and running
but not published. A zero there would have read as a measurement.

One proxy replaces the P-only one. /v1/pchain hardcoded /v1/bc/P; /v1/node/
<endpoint> resolves the endpoint against the primary-chain table and never
treats it as a URL. A chain the gateway does not route comes back 200 carrying
a JSON-RPC error rather than 502 — nothing is broken, and 502 put a red failed
request in the console of eight of the ten chain pages.

Deleted: CHAIN_INDEXER_URLS and the hook that read it — fifteen hostnames of
the shape api-indexer-<x>chain.lux.network, none of which resolve. Fifteen of
fifteen NXDOMAIN. It fetched them on every chain page and rendered the null.

Measured on mainnet, 1440x900 and 390x844, fresh context per URL: 20 of 20
chain/screen rows agree with RPC on both status and head — C-Chain 1,107,826
against a live head bracketed at 1,107,822..1,107,829, P and X at 0, seven
reading No public RPC, Q Syncing while the rest are Bootstrapped. /chains
lists the same ten chains the P-Chain reports, and 10 of 10 row links reach a
real page. Zero 4xx or 5xx from our own origin.
2026-08-08 07:32:01 -07:00

55 lines
1.5 KiB
TypeScript

// React Query hook for platform.getBlockchains.
// Returns the list of all blockchains registered on the P-chain.
// Uses the server-side /v1/node/p-chain proxy to bypass CORS.
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import type { PChainBlockchain } from './types';
const BLOCKCHAINS_STALE_TIME_MS = 300_000;
const BLOCKCHAINS_QUERY_KEY = 'pchain:blockchains' as const;
const EMPTY_BLOCKCHAINS: ReadonlyArray<PChainBlockchain> = [];
async function fetchBlockchains(): Promise<ReadonlyArray<PChainBlockchain>> {
const res = await fetch('/v1/node/p-chain', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'platform.getBlockchains',
params: {},
id: 1,
}),
});
if (!res.ok) {
throw new Error(`P-chain proxy returned ${ res.status }`);
}
const json = await res.json() as { result?: { blockchains?: ReadonlyArray<PChainBlockchain> } };
return json.result?.blockchains ?? [];
}
export function useBlockchains() {
const query = useQuery({
queryKey: [ BLOCKCHAINS_QUERY_KEY ],
queryFn: fetchBlockchains,
staleTime: BLOCKCHAINS_STALE_TIME_MS,
retry: 2,
});
const blockchains = React.useMemo(
() => query.data ?? EMPTY_BLOCKCHAINS,
[ query.data ],
);
return {
blockchains,
isLoading: query.isLoading,
isError: query.isError,
error: query.error,
refetch: query.refetch,
};
}