noter: report a scan group in one batch, count progress as liveness (#34)

The first scan after the Zagros People upgrade re-confirmed all 98
accounts, one transaction per account, a block each. It ran past the
15-minute staleness window and the watchdog killed it halfway; the next
interval had meanwhile started a second scan beside it, which read the
same accounts before the first one's reports landed and sent them again
(124 submissions for 98 accounts). On mainnet every tracked citizen's
re-confirmation falls due in the same scan, every three days.

- A scan group's updates go out as one utility.forceBatch. The accounts
  are unrelated, so one refused report no longer takes the others with
  it; each refused item is logged with its decoded error.
- The heartbeat records progress -- a group read and, if it had anything
  to report, reported -- instead of a finished scan. A group that cannot
  be read, or whose report is refused outright, is not progress, so a
  mute noter still goes stale.
- A periodic scan does not start while the previous one is running.
This commit is contained in:
SatoshiQaziMuhammed authored and GitHub committed 2026-10-20 10:25:57 +04:00
1 parent 0220302a98
commit cb25e08547
4 files changed
+179 -25

No files matched your search

+3 -3
View File
@@ -163,9 +163,9 @@ services:
ASSET_HUB_RPC: wss://asset-hub-rpc.pezkuwichain.io
PEOPLE_RPC: wss://people-rpc.pezkuwichain.io
SCAN_INTERVAL_MS: "300000"
# The bot writes a heartbeat when a scan completes, not when it merely stays
# up: an endless reconnect loop kept the container "Up" for three weeks while
# no staking data reached the People chain.
# The bot writes a heartbeat when a scan makes progress, not when it merely
# stays up: an endless reconnect loop kept the container "Up" for three weeks
# while no staking data reached the People chain.
healthcheck:
test: ["CMD", "node", "-e", "const fs=require('fs');const i=parseInt(process.env.SCAN_INTERVAL_MS||'300000',10);let t=0;try{t=Number(fs.readFileSync(process.env.HEARTBEAT_FILE||'/tmp/noter-heartbeat','utf8'))}catch{};process.exit(Number.isFinite(t)&&Date.now()-t<i*3?0:1)"]
interval: 60s