Quantus arena: network hashrate, authorship leaderboard, telemetry census #2

Open
opened 2026-08-31 16:50:07 +00:00 by grenade · 1 comment
Owner

A public-ish dashboard for everyone mining Quantus: what the network hashrate is, who is actually winning blocks, and what the node population looks like. Supersedes the observability blocker in #1 — the chain-scraper half of this is the missing measurement.

All the plumbing was verified against the live Planck network on 2026-08-31; details below so none of it needs rediscovering.

Source 1 — the chain (authoritative)

Everything needed is on our own node's RPC. No third party, no trust.

Block author. Every header carries the miner's reward preimage in a PreRuntime digest. Decoded from a live header:

06        DigestItem::PreRuntime
706f775f  engine id "pow_"
80        SCALE compact length = 32
3e31b55d177ffe21d458e40e5b551560a10f6d6d9f883e2f7afab8ac13b9001b
          the author's inner_hash

address = Poseidon2(inner_hash) — same derivation as qp_wormhole::derive_wormhole_address, and extract_author_from_digest in primitives/wormhole already does exactly this. So a complete per-address authorship leaderboard is derivable from headers alone, for every miner on the network, with no cooperation from anyone.

Difficulty. No RPC method exposes it directly (rpc_methods has nothing matching), but two routes exist:

  • Runtime API QPoWApi::get_difficulty() / get_max_difficulty() (primitives/consensus/qpow), also verify_and_get_achieved_difficulty(block_hash, nonce) for per-block achieved difficulty
  • Storage QPoW::CurrentDifficulty via state_getStorage, key twox128("QPoW") ++ twox128("CurrentDifficulty")

Then network hashrate ≈ difficulty / 6s, and our share is miner_hash_rate ÷ that.

This is the piece worth building first, independent of the dashboard: it is what tests the competition thesis on launch day, and it closes #1.

Source 2 — telemetry (population and colour)

wss://feed-telemetry.quantus.cat/feed — found in /tmp/env-config.js on telemetry.quantus.com, not the /feed path on the main host, which 404s. Standard substrate-telemetry protocol: connect, send subscribe:<genesis_hash>, receive JSON arrays of [action_code, payload, …] pairs.

Planck genesis: 0x4901bf5c57fd3f9e726af399c763de6670dbdb115a91c0237e173f16eef65e72

Verified working. Action 11 reported 30 nodes on Planck. Action 3 (AddedNode) carries a richer payload than expected:

[1, ["QuantusNodeLIVE", "Quantus Node", "0.10.0-37ac3db8165", null,
     "QmQNmrxUbbwvtDeCUkkWk3cu66mtPpffEjbXsXgaQT1iqN",
     "linux", "x86_64", "gnu", null,
     {"cpu": "AMD EPYC 9354P 32-Core Processor", "memory": 8326635520,
      "core_count": 2, "linux_kernel": "6.8.0-117-generic",
      "linux_distro": "Ubuntu 24.04.4 LTS", "is_virtual_machine": true}, null],
 [29, 0], [[block timings…]]]

So a genuine hardware census is available: CPU model, RAM, core count, distro, kernel, and whether it is a VM. Node name, client version and peer id too.

The correlation is the hard part — and it is not directly possible

Telemetry identifies nodes by name and peer id. The chain identifies miners by reward address. Nothing links the two. A node's peer id does not appear in the blocks it authors, and the reward preimage says nothing about which node submitted it.

Three options, in descending order of honesty:

  1. Ground truth for our own node. We know both sides (baba-gorchitsa / QmUQ4o9kc…qzp2AxZw…). One confirmed data point, and useful for validating any heuristic.
  2. Voluntary self-registration. Miners opt in by publishing their node name alongside their reward address. Turns the arena into something people join rather than something done to them — probably the right social shape for a "bit of fun" dashboard anyway.
  3. Timing heuristic. The authoring node imports and announces its own block before anyone else, so telemetry's per-node best-block updates should show the author reaching height N marginally first. Over many blocks that is a statistical attribution. Genuinely interesting, definitely noisy, and must be labelled probabilistic if shown at all. Option 1 gives a way to measure how well it works: we know when we authored, so we can check whether the heuristic picks us.

Do not present 3 as fact. Misattributing hashrate to named operators would be both wrong and rude.

Suggested shape

  • Small Rust or Python exporter on the node host: subscribes to chain_subscribeNewHeads, decodes author from the digest, reads difficulty, exposes Prometheus metrics — quantus_difficulty, quantus_network_hashrate, quantus_blocks_authored_total{address=…}.
  • Second exporter (or the same one) holding the telemetry websocket, exposing node counts, version and hardware distribution.
  • Grafana panels alongside the existing dashboard. Public exposure is a separate decision — the current Grafana is unauthenticated and mesh-only, so "for everyone who is mining" needs a plan that is not "open Grafana to the WAN".

Priority against 2026-09-09

The difficulty and authorship exporter is pre-launch work — without it we cannot measure our share on day one, which is the whole question. The telemetry census and the arena presentation are post-launch polish. Do not let the fun half delay the useful half.

A public-ish dashboard for everyone mining Quantus: what the network hashrate is, who is actually winning blocks, and what the node population looks like. Supersedes the observability blocker in #1 — the chain-scraper half of this *is* the missing measurement. All the plumbing was verified against the live Planck network on 2026-08-31; details below so none of it needs rediscovering. ## Source 1 — the chain (authoritative) Everything needed is on our own node's RPC. No third party, no trust. **Block author.** Every header carries the miner's reward preimage in a PreRuntime digest. Decoded from a live header: ``` 06 DigestItem::PreRuntime 706f775f engine id "pow_" 80 SCALE compact length = 32 3e31b55d177ffe21d458e40e5b551560a10f6d6d9f883e2f7afab8ac13b9001b the author's inner_hash ``` `address = Poseidon2(inner_hash)` — same derivation as `qp_wormhole::derive_wormhole_address`, and `extract_author_from_digest` in `primitives/wormhole` already does exactly this. So **a complete per-address authorship leaderboard is derivable from headers alone**, for every miner on the network, with no cooperation from anyone. **Difficulty.** No RPC method exposes it directly (`rpc_methods` has nothing matching), but two routes exist: - Runtime API `QPoWApi::get_difficulty()` / `get_max_difficulty()` (`primitives/consensus/qpow`), also `verify_and_get_achieved_difficulty(block_hash, nonce)` for per-block achieved difficulty - Storage `QPoW::CurrentDifficulty` via `state_getStorage`, key `twox128("QPoW") ++ twox128("CurrentDifficulty")` Then `network hashrate ≈ difficulty / 6s`, and our share is `miner_hash_rate ÷ that`. **This is the piece worth building first**, independent of the dashboard: it is what tests the competition thesis on launch day, and it closes #1. ## Source 2 — telemetry (population and colour) `wss://feed-telemetry.quantus.cat/feed` — found in `/tmp/env-config.js` on telemetry.quantus.com, *not* the `/feed` path on the main host, which 404s. Standard substrate-telemetry protocol: connect, send `subscribe:<genesis_hash>`, receive JSON arrays of `[action_code, payload, …]` pairs. Planck genesis: `0x4901bf5c57fd3f9e726af399c763de6670dbdb115a91c0237e173f16eef65e72` Verified working. Action 11 reported **30 nodes** on Planck. Action 3 (AddedNode) carries a richer payload than expected: ```json [1, ["QuantusNodeLIVE", "Quantus Node", "0.10.0-37ac3db8165", null, "QmQNmrxUbbwvtDeCUkkWk3cu66mtPpffEjbXsXgaQT1iqN", "linux", "x86_64", "gnu", null, {"cpu": "AMD EPYC 9354P 32-Core Processor", "memory": 8326635520, "core_count": 2, "linux_kernel": "6.8.0-117-generic", "linux_distro": "Ubuntu 24.04.4 LTS", "is_virtual_machine": true}, null], [29, 0], [[block timings…]]] ``` So a genuine hardware census is available: CPU model, RAM, core count, distro, kernel, and whether it is a VM. Node name, client version and peer id too. ## The correlation is the hard part — and it is not directly possible Telemetry identifies nodes by **name and peer id**. The chain identifies miners by **reward address**. Nothing links the two. A node's peer id does not appear in the blocks it authors, and the reward preimage says nothing about which node submitted it. Three options, in descending order of honesty: 1. **Ground truth for our own node.** We know both sides (`baba-gorchitsa` / `QmUQ4o9kc…` ↔ `qzp2AxZw…`). One confirmed data point, and useful for validating any heuristic. 2. **Voluntary self-registration.** Miners opt in by publishing their node name alongside their reward address. Turns the arena into something people join rather than something done to them — probably the right social shape for a "bit of fun" dashboard anyway. 3. **Timing heuristic.** The authoring node imports and announces its own block before anyone else, so telemetry's per-node best-block updates should show the author reaching height N marginally first. Over many blocks that is a statistical attribution. Genuinely interesting, definitely noisy, and must be labelled probabilistic if shown at all. Option 1 gives a way to measure how well it works: we know when we authored, so we can check whether the heuristic picks us. **Do not present 3 as fact.** Misattributing hashrate to named operators would be both wrong and rude. ## Suggested shape - Small Rust or Python exporter on the node host: subscribes to `chain_subscribeNewHeads`, decodes author from the digest, reads difficulty, exposes Prometheus metrics — `quantus_difficulty`, `quantus_network_hashrate`, `quantus_blocks_authored_total{address=…}`. - Second exporter (or the same one) holding the telemetry websocket, exposing node counts, version and hardware distribution. - Grafana panels alongside the existing dashboard. Public exposure is a separate decision — the current Grafana is unauthenticated and mesh-only, so "for everyone who is mining" needs a plan that is not "open Grafana to the WAN". ## Priority against 2026-09-09 The **difficulty and authorship exporter is pre-launch work** — without it we cannot measure our share on day one, which is the whole question. The telemetry census and the arena presentation are post-launch polish. Do not let the fun half delay the useful half.
Author
Owner

Prior art: Quantus-Network/qsafe.af

An earlier version of exactly this already exists — a Substrate explorer written against the pre-Planck Quantus protocols. Archived, last pushed 2025-10-13, 101 files, Vite + React + TypeScript (which matches generic.md §4 anyway). Live at https://qsafe.af.

Already built, and directly relevant:

  • src/components/MiningStats.tsx — miner leaderboard with per-miner block counts and percentage share
  • src/components/Nodes.tsx — telemetry websocket client, same subscribe:<genesis> protocol confirmed above
  • src/chains.ts — per-chain config: genesis, RPC endpoints, indexer, treasury, telemetry URL
  • ML-DSA / Poseidon awareness, SS58 formatting, runtime-aware extrinsic and event decoding

So the frontend, the telemetry handling and the leaderboard UI do not need inventing. Three things need changing.

1. It is a pure SPA with no backend, and leans on a GraphQL indexer

schrodinger: {
  endpoints: ["wss://quantu.se"],
  indexer: "https://quantu.se/graphql",
  telemetry: "wss://tc0.res.fm/feed",
}

MiningStats derives miners from balance events (event.balanceEvent?.account?.id) — the reward deposit credits the miner — which needs either an indexer or a lot of browser-side block fetching. The code carries a zero-address guard and a first-valid-miner-per-block dedup pass, which reads like it was fighting event ambiguity.

The PreRuntime digest approach in the issue above is strictly better for this: headers only (no full blocks, no metadata, no event decoding), unambiguous by construction, and it is what the runtime itself does. It also removes the indexer dependency entirely — which matters, because we would otherwise be depending on quantu.se staying up.

Suggested split: compute the leaderboard in an exporter on our own node from headers, serve it as metrics/JSON, and let the SPA read that. Then the arena has no third-party runtime dependency at all.

2. Every chain in it predates Planck

schrodinger (Quantus Testnet), resonance, heisenberg. Planck needs adding, then mainnet after 2026-09-09:

genesis:   0x4901bf5c57fd3f9e726af399c763de6670dbdb115a91c0237e173f16eef65e72
telemetry: wss://feed-telemetry.quantus.cat/feed      (was wss://tc0.res.fm/feed)
endpoints: ???

endpoints is the open question — a browser SPA needs a public wss RPC. Ours is bound to 127.0.0.1:9944 and should stay that way. Either find a public Quantus RPC, or have the exporter serve what the arena needs so the SPA never talks to a node directly. The second is preferable and follows from §1.

3. It is archived

Needs unarchiving upstream, or forking to lair/. Given the chain-side changes and the shift away from the indexer, a fork we control is probably the honest option — with a note in the fork pointing back, per generic.md §11 Source hosting.

Revised priority

Unchanged in substance, but cheaper than estimated: the exporter is still the pre-launch work, and the prior art means the presentation layer is mostly a config-and-refit job rather than a build. The leaderboard maths, the telemetry client and the UI already exist and were written by the same person who now wants them back.

## Prior art: `Quantus-Network/qsafe.af` An earlier version of exactly this already exists — a Substrate explorer written against the pre-Planck Quantus protocols. **Archived**, last pushed 2025-10-13, 101 files, Vite + React + TypeScript (which matches `generic.md` §4 anyway). Live at https://qsafe.af. Already built, and directly relevant: - `src/components/MiningStats.tsx` — miner leaderboard with per-miner block counts and percentage share - `src/components/Nodes.tsx` — telemetry websocket client, same `subscribe:<genesis>` protocol confirmed above - `src/chains.ts` — per-chain config: genesis, RPC endpoints, indexer, treasury, telemetry URL - ML-DSA / Poseidon awareness, SS58 formatting, runtime-aware extrinsic and event decoding So the frontend, the telemetry handling and the leaderboard UI do not need inventing. Three things need changing. ### 1. It is a pure SPA with no backend, and leans on a GraphQL indexer ```ts schrodinger: { endpoints: ["wss://quantu.se"], indexer: "https://quantu.se/graphql", telemetry: "wss://tc0.res.fm/feed", } ``` `MiningStats` derives miners from **balance events** (`event.balanceEvent?.account?.id`) — the reward deposit credits the miner — which needs either an indexer or a lot of browser-side block fetching. The code carries a zero-address guard and a first-valid-miner-per-block dedup pass, which reads like it was fighting event ambiguity. **The PreRuntime digest approach in the issue above is strictly better** for this: headers only (no full blocks, no metadata, no event decoding), unambiguous by construction, and it is what the runtime itself does. It also removes the indexer dependency entirely — which matters, because we would otherwise be depending on `quantu.se` staying up. Suggested split: compute the leaderboard in an exporter on our own node from headers, serve it as metrics/JSON, and let the SPA read that. Then the arena has no third-party runtime dependency at all. ### 2. Every chain in it predates Planck `schrodinger` (Quantus Testnet), `resonance`, `heisenberg`. Planck needs adding, then mainnet after 2026-09-09: ``` genesis: 0x4901bf5c57fd3f9e726af399c763de6670dbdb115a91c0237e173f16eef65e72 telemetry: wss://feed-telemetry.quantus.cat/feed (was wss://tc0.res.fm/feed) endpoints: ??? ``` `endpoints` is the open question — a browser SPA needs a **public** wss RPC. Ours is bound to `127.0.0.1:9944` and should stay that way. Either find a public Quantus RPC, or have the exporter serve what the arena needs so the SPA never talks to a node directly. The second is preferable and follows from §1. ### 3. It is archived Needs unarchiving upstream, or forking to `lair/`. Given the chain-side changes and the shift away from the indexer, a fork we control is probably the honest option — with a note in the fork pointing back, per `generic.md` §11 Source hosting. ### Revised priority Unchanged in substance, but cheaper than estimated: **the exporter is still the pre-launch work**, and the prior art means the presentation layer is mostly a config-and-refit job rather than a build. The leaderboard maths, the telemetry client and the UI already exist and were written by the same person who now wants them back.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lair/quantus#2