Caches what the telemetry feed says each node *is*, and surfaces it on the miner route: client version, target triple, CPU, cores, memory, kernel, distribution, whether it is virtualised, country, and how long the node process has been up. Kept in `node_telemetry`, keyed by peer id — never by the feed's `node_id`, which is per-connection and would accumulate a row per reconnect for the same machine. Written every five minutes rather than every thirty seconds like the attributions beside it: a CPU does not change, and mainnet alone has nearly three hundred nodes. The route reads the live feed first and the cache second, so a node the feed has not re-announced since our last restart still answers. Nulls never overwrite. The telemetry server geolocates asynchronously, so every reconnect re-sends every node with a null location — a naive upsert would blank the country of every node on the site for as long as the lookups took to catch up. The guard is in the feed state and in the `on conflict` clause both, with a test for each. **Location is a country and no finer.** The feed sends coordinates and a city from an IP geolocation database, and at city resolution those are wrong often enough that showing one would assert something nobody knows. `blackbeard_core::geo` derives the country offline from a 508 KiB boundary set — no network call, and nothing told where these nodes are — and the coordinates are then dropped. The schema has no city, latitude or longitude column: a column that does not exist cannot be rendered by mistake. The lookup returns subdivisions before countries and `GB-ENG` is exactly the precision being avoided, so only the two-letter code survives. **The panel wears its uncertainty in the header, not a footnote.** A miner is joined to a node by the same first-reporter voting that gives it a display name, so `Attribution` now carries the peer id it settled on — `None` for a preimage or a carried name, because there is no node behind either. The heading reads "reported by" and the confidence and vote count sit beside it. The note says the CPU is the node's and not necessarily what is hashing: on this network the work is on GPUs that telemetry does not report at all. Checked against the live feed end to end, not a fixture: real frames decoded, cached, served and rendered. One node reports an Ubuntu userspace on a Fedora kernel, which is a container seeing its host — the panel shows that faithfully rather than tidying it away. Closes #15 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
50 lines
2.4 KiB
SQL
50 lines
2.4 KiB
SQL
-- What the telemetry feed says a node is, kept across restarts.
|
|
--
|
|
-- Keyed on the peer id, never on the feed's `node_id`: that one is per
|
|
-- connection and changes every time the telemetry server restarts or the node
|
|
-- reconnects, so a table keyed on it would accumulate a new row per reconnect
|
|
-- for the same machine.
|
|
--
|
|
-- One row per node, overwritten whenever the feed says something newer. There
|
|
-- is deliberately no history: this is a cache of the current answer, and a node
|
|
-- that changes its CPU is telling us the old answer was superseded rather than
|
|
-- adding a fact about the past.
|
|
create table if not exists node_telemetry (
|
|
peer_id text primary key,
|
|
-- Which chain we last saw it on. A node reports to one chain's feed, but
|
|
-- an operator may move a machine between chains, and the row follows it.
|
|
chain text not null references chain (id) on delete cascade,
|
|
name text not null,
|
|
implementation text,
|
|
version text,
|
|
target_os text,
|
|
target_arch text,
|
|
target_env text,
|
|
cpu text,
|
|
core_count integer,
|
|
-- Bytes. `bigint` because 64 GiB does not fit in an integer, and the
|
|
-- machines on this network routinely have more.
|
|
memory bigint,
|
|
linux_kernel text,
|
|
linux_distro text,
|
|
is_virtual_machine boolean,
|
|
-- ISO 3166-1 alpha-2, derived from coordinates we do not keep.
|
|
--
|
|
-- No city column, and no latitude or longitude, by design: the feed's
|
|
-- coordinates come from IP geolocation and are wrong at city resolution
|
|
-- often enough that storing them would invite someone to render one. A
|
|
-- column that does not exist cannot be displayed by mistake.
|
|
country_code text,
|
|
country_name text,
|
|
-- When the node process started, per the feed. Lets uptime be a fact about
|
|
-- the node rather than about how long this observer has been watching.
|
|
startup_time timestamptz,
|
|
-- When we last heard any of this.
|
|
seen_at timestamptz not null default now()
|
|
);
|
|
|
|
-- The join the miner route makes: attribution gives a peer id, and rows are
|
|
-- read one at a time by it — which the primary key already serves. This index
|
|
-- is for the other direction, listing a chain's nodes.
|
|
create index if not exists node_telemetry_chain_idx on node_telemetry (chain, seen_at desc);
|