diff --git a/asset/arena/quantus-arena-exporter.py b/asset/arena/quantus-arena-exporter.py index 4db2c10..d9aa8b7 100755 --- a/asset/arena/quantus-arena-exporter.py +++ b/asset/arena/quantus-arena-exporter.py @@ -369,6 +369,9 @@ ATTRIBUTION_MIN_CONFIDENCE = 0.6 # restarts or renames (a new telemetry node id) takes over the attribution # after a few blocks instead of having to outvote its own history. ATTRIBUTION_WINDOW = 20 +# Startup backfill of the rolling window from chain history is capped by +# wall clock so a slow node cannot hold the exporter's first poll forever. +BACKFILL_BUDGET_S = 180.0 GAP_BUCKETS = [0.5, 1, 2, 3, 5, 8, 12, 16, 24, 32, 48, 64, 128] # Block timestamp minus the moment this exporter first saw the block, seconds. @@ -534,6 +537,32 @@ class Arena: return None return self.rpc.call("chain_getHeader", [h]) + def backfill_window(self, height): + """Fill the rolling window from chain history at startup, so the + per-author series (leaderboard rows, author labels, timing caps) do + not start from nothing after every restart. Window only: the authored + counter is left alone so `increase()` sees no phantom burst, and no + tip timing is observed for blocks we did not watch arrive.""" + start = max(1, height - self.blocks.maxlen + 1) + deadline = time.time() + BACKFILL_BUDGET_S + n = start + got = 0 + while n < height and time.time() < deadline: + try: + hdr = self.header_at(n) + except Exception as e: # noqa: BLE001 - history is best effort + LOG.warning("backfill stopped at %s: %s", n, e) + break + if hdr: + pre = author_preimage(hdr) + if pre is not None: + with self.lock: + self.blocks.append((n, pre)) + got += 1 + n += 1 + LOG.info("backfilled %s of %s window blocks (%s..%s) in %.0fs", got, height - start, start, n - 1, + time.time() - (deadline - BACKFILL_BUDGET_S)) + def record(self, header, at_tip): height = int(header["number"], 16) pre = author_preimage(header) @@ -636,6 +665,8 @@ class Arena: hdr = self.header_at(n) if hdr: self.record(hdr, at_tip=False) + if self.last_height is None: + self.backfill_window(height) if self.last_height is None or height > self.last_height: self.record(head, at_tip=not self.syncing) self.last_height = height diff --git a/asset/grafana/quantus.json b/asset/grafana/quantus.json index 27be047..be70281 100644 --- a/asset/grafana/quantus.json +++ b/asset/grafana/quantus.json @@ -9,7 +9,7 @@ ], "timezone": "browser", "schemaVersion": 39, - "version": 21, + "version": 22, "refresh": "30s", "time": { "from": "now-6h", @@ -1725,7 +1725,7 @@ }, "editorMode": "code", "refId": "A", - "expr": "sort_desc(topk(20, round(increase(quantus_blocks_authored_total[$__range]))))", + "expr": "sort_desc(topk(20, round(increase(quantus_blocks_authored_total[$__range])) > 0))", "instant": true, "range": false, "format": "table"