Cargo workspace plus a Vite frontend, following ~/git/architecture/generic.md. Every block header carries its author's wormhole reward preimage in a `pow_` PreRuntime digest, so authorship for the whole network is derivable from headers alone — no indexer, no registration, no way for a miner to be left out. That decoding, the hashrate maths and the telemetry name attribution live in blackbeard-core with no I/O at all, so the parts that are easy to get subtly wrong are exercised by unit tests rather than only against a live chain. The browser holds one WebSocket: snapshot on subscribe, deltas thereafter. The head stream is itself a push (chain_subscribeNewHeads), so a block reaches the page the moment the node imports it. Messages are serialised once per broadcast, and leaderboards are recomputed only for windows a socket is actually watching. No RxJS — useSyncExternalStore is React's own contract for this. Verified against the live Planck testnet: 12/12 headers decoded, telemetry names attributed (quanpool-planck, baba-gorchitsa, …), warm start restoring 84 blocks and 5 held names across a restart. Three findings worth recording, all in CLAUDE.md: - substrate-telemetry sends its JSON in *binary* frames. A text-only client connects, subscribes, reports healthy and receives nothing at all — and a Python probe hides it, because json.loads accepts bytes. - Difficulty is a little-endian U512; decoding it big-endian gives a number wrong by ~10^150 that still renders fine. - Planck's real block interval is ~13-15s against a 6s target with enormous variance, so a measured interval needs 20 tip samples before it is publishable. Deploy assets, the Gitea Actions workflow and script/infra-setup.sh are included; port 25864 is registered in architecture/port-allocations.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSDYiibCtELsrjQq6KXnoi
37 lines
1.5 KiB
HTML
37 lines
1.5 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>blackbeard.observer — Quantus mining leaderboard</title>
|
|
<meta
|
|
name="description"
|
|
content="Live miner leaderboard and network hashrate for the Quantus blockchain and its Planck testnet. Every author decoded from block headers — no registration, no opt-in."
|
|
/>
|
|
<meta name="color-scheme" content="dark" />
|
|
<!-- Painted before the stylesheet loads, so there is no white flash on a
|
|
page whose entire design is dark. -->
|
|
<meta name="theme-color" content="#0d0b09" />
|
|
<link rel="icon" href="/sigil.svg" type="image/svg+xml" />
|
|
|
|
<meta property="og:title" content="blackbeard.observer" />
|
|
<meta property="og:description" content="Live Quantus mining leaderboard and network hashrate." />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:url" content="https://blackbeard.observer/" />
|
|
|
|
<style>
|
|
/* Inline so the background is right on the first paint rather than after
|
|
the CSS bundle arrives. */
|
|
html { background: #0d0b09; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="root"></div>
|
|
<noscript>
|
|
blackbeard.observer streams the chain over a WebSocket and needs JavaScript. The same data is
|
|
available without it from the API at <code>/v1/chains</code>.
|
|
</noscript>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|