diff --git a/asset/grafana/quantus.json b/asset/grafana/quantus.json index aceba32..600150b 100644 --- a/asset/grafana/quantus.json +++ b/asset/grafana/quantus.json @@ -9,7 +9,7 @@ ], "timezone": "browser", "schemaVersion": 39, - "version": 1, + "version": 2, "refresh": "30s", "time": { "from": "now-6h", @@ -1073,6 +1073,191 @@ } }, "description": "Counter derivative \u2014 the honest check that work is being done, independent of the reported gauge." + }, + { + "type": "row", + "title": "Mining efficiency", + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 33 + }, + "panels": [] + }, + { + "type": "timeseries", + "title": "Mining rounds started (per min)", + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 34 + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(rate(substrate_proposer_block_constructed_count{job=\"quantus-node\"}[5m])) * 60", + "legendFormat": "rounds/min", + "range": true, + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "lineWidth": 2, + "fillOpacity": 8, + "showPoints": "never" + }, + "color": { + "mode": "palette-classic" + }, + "unit": "none" + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "description": "Each new best tip makes the node construct a fresh block proposal and hand the miner a new job. Once synced this should track the network's block rate \u2014 about 10/min at a 6s target. Persistently below that means the node is learning about tips late, which is the connectivity effect peer count is supposed to improve. Near zero while syncing is normal: the node does not author until it is caught up." + }, + { + "type": "timeseries", + "title": "Hashes per mining round", + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 34 + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(rate(miner_hashes_total{job=\"quantus-miner\"}[5m])) / sum(rate(substrate_proposer_block_constructed_count{job=\"quantus-node\"}[5m]))", + "legendFormat": "hashes/round", + "range": true, + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "lineWidth": 2, + "fillOpacity": 8, + "showPoints": "never" + }, + "color": { + "mode": "palette-classic" + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "description": "Work completed per round. Expected hashes per block is the network difficulty, so hashes-per-round \u00f7 difficulty is the per-round win probability \u2014 but difficulty is NOT exported by either binary, so that division cannot be plotted. Absolute value is still useful as a trend: a fall means rounds are being cut short by incoming tips." + }, + { + "type": "timeseries", + "title": "Active jobs", + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 34 + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "miner_active_jobs{job=\"quantus-miner\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "lineWidth": 2, + "fillOpacity": 8, + "showPoints": "never" + }, + "color": { + "mode": "palette-classic" + }, + "unit": "none" + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "description": "Jobs in flight. Should be continuously non-zero once the node is synced. Gaps mean the miner is idle \u2014 either the node has no work, or the QUIC link dropped." + }, + { + "type": "text", + "title": "What this row cannot tell you yet", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 42 + }, + "options": { + "mode": "markdown", + "content": "**Blocks actually authored is not observable from these exporters.**\n\n`quantus-node` exports no difficulty metric and no authored-block counter \u2014 `substrate_proposer_block_constructed` counts proposals *constructed*, not rounds *won*. `quantus-miner` exports no solutions-found counter either (`miner_hashes_total`, `miner_hash_rate`, `miner_active_jobs`, worker/device gauges, and nothing else).\n\nSo the question worth answering \u2014 *do we win the share of blocks our hashrate predicts?* \u2014 cannot currently be plotted. That ratio is the real measure of orphan and stale-work loss, and therefore the only honest test of whether tuning peer count or anything else helped.\n\nClosing that gap needs one of: an upstream metric for difficulty and blocks authored, a log-derived exporter, or a periodic chain query counting blocks credited to the reward address. Tracked in the repo's issues \u2014 read that before drawing conclusions from the panels above." + } } ] } diff --git a/readme.md b/readme.md index 6fcb545..d33b528 100644 --- a/readme.md +++ b/readme.md @@ -97,6 +97,14 @@ instead of every project editing one file, and `grafana.container` gained a dashboards bind mount — it previously mounted only the datasource. Both are additive, guarded, and back up what they touch. +**What the dashboard cannot tell you:** neither binary exports a difficulty +metric or an authored-block counter, and the miner exports no solutions-found +counter — so "do we win the share of blocks our hashrate predicts?", the only +honest measure of orphan and stale-work loss, is not plottable today. The +"Mining efficiency" row shows the measurable proxies and says so explicitly. +Closing that gap, and the experiments that depend on it, are tracked in +[issue #1](https://git.lair.cafe/lair/quantus/issues/1). + The dashboard is provisioned with `allowUiUpdates: false`: edit the JSON here and redeploy, so a browser tweak cannot silently diverge from source.