igneum/tools/observer
igneum-labs d93606554a Live devnet: observer, /api/live and the /live page
tools/observer: Node 22 observer on the node's wRPC JSON port (blockAdded and
virtualChainChanged subscriptions, 2 s state ticks) writing live_blocks,
live_state and live_events to Neon, miner address decoded from the coinbase
payload, events for new or quiet miners, peers and difficulty steps.
site/api/live.mjs: three indexed queries, max-age=1.
site/live.html: status strip, DAG stream with real parent edges and a lane per
miner, miners table, events feed, blocks-per-minute sparkline, OFFLINE freeze.
The homepage live path and the /api/live cache header went in with 408c968.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 19:22:06 +00:00
..
observer.mjs Live devnet: observer, /api/live and the /live page 2026-10-03 19:22:06 +00:00
README.md Live devnet: observer, /api/live and the /live page 2026-10-03 19:22:06 +00:00

Igneum devnet observer

Watches one Igneum node over wRPC JSON and writes what it sees to Neon, so /api/live and /live on the site can show the devnet as it runs. Node 22 or newer, no dependencies.

Run

node tools/observer/observer.mjs

Environment, every value optional:

Variable Default Meaning
IGNEUM_RPC ws://127.0.0.1:28610 The node's wRPC JSON url. 28610 is the igneum-devnet wRPC JSON port (consensus/core/src/network.rs). Start the node with --rpclisten-json=127.0.0.1:28610 or the port of your choice.
DATABASE_URL read from ~/.config/igneum/env Neon connection string. Never commit it.
LIVE_RETAIN_HOURS 24 Hours of blocks kept in live_blocks. Older rows are deleted once a minute.

A node started by another tool may listen on gRPC only. Then run your own non-mining peer with a JSON listener, on ports that do not clash with the devnet's (gRPC 26610, P2P 26611):

vendor/igneum-node/target/release/kaspad --devnet --nodnsseed --disable-upnp \
  --appdir=/tmp/igneum-obsnode --rpclisten=127.0.0.1:26640 --rpclisten-json=127.0.0.1:28640 \
  --listen=127.0.0.1:26641 --connect=127.0.0.1:26611 --nologfiles
IGNEUM_RPC=ws://127.0.0.1:28640 node tools/observer/observer.mjs

What it does

  • Subscribes to blockAdded and virtualChainChanged; polls getBlockDagInfo, getInfo, getConnectedPeerInfo, getSinkBlueScore and estimateNetworkHashesPerSecond every 2 s.
  • Decodes the miner address from the coinbase payload script (same bech32 variant as crypto/addresses). The fork's vote_key_hash header field is stored per block; the first 8 hex characters are the miner's short id on the site.
  • engine is the miner's tag in the coinbase extra data after the node's version prefix. The node exposes no engine name over RPC, so this is null on devnet v0.
  • When the node refuses the hash-rate estimate (it needs a 1,000-block window) the observer reports blue work added per second over the last 10 minutes instead.

Tables

Created on start if missing.

Table Rows Columns
live_blocks one per block, kept LIVE_RETAIN_HOURS hash, blue_score, daa_score, timestamp_ms, parents (count), parent_hashes, is_chain_block, vote_key_hash, miner_address, engine, received_at. Indexes on received_at, timestamp_ms, (vote_key_hash, received_at).
live_state one row, updated every 2 s block_count, header_count, blue_score, difficulty, hashes_per_second_estimate, peers, mempool, node_version, network, blocks_60s, blocks_per_minute (60 pairs of minute epoch ms and count), observer_started_at, updated_at
live_events one per event, kept 7 days ts, kind, text. Kinds: observer, miner_seen, miner_quiet, miner_back, peer_joined, peer_left, difficulty (step over 5%). Checkpoints will be added when the finality layer lands.

Reading it

site/api/live.mjs serves /api/live from these tables in three indexed queries. site/live.html polls it every 2 s. The site shows OFFLINE when live_state.updated_at is older than 30 s.