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.
Zagros citizens have no trust until a noter reports their stake, so every
Zagros governance track stalls without one. Until now the Zagros noter ran
by hand from a workstation and stopped whenever that machine slept.
The same image runs as noter-zagros, against the Zagros endpoints, with
its own key and heartbeat. The bot reads its key from
/run/secrets/noter_mnemonic, so the Zagros secret is mounted under that
name and the bot needs no change.
The secret file must exist on the host before this deploys: compose
refuses to bring up the stack with a missing secret file.
The bot pointed at the block-producing nodes' RPC ports. Those bind to
localhost, so once they stopped being exposed to the internet the bot lost
every chain at once and has submitted nothing since. `staking_score` gates
the entire trust score, so a noter that cannot reach the chains does not
degrade the score — it zeroes it for every tracked account.
Point it at the public endpoints instead, which is what an external client
should use and what the code already defaulted to. They are TLS-terminated
rather than plaintext ws:// across the internet, and this drops a hardcoded
node address from the repository.
Reaching the chains again is not enough on its own: the outage lasted three
weeks because reconnecting forever looks identical to working. The bot now
writes a heartbeat when a scan *completes*, a container healthcheck reads it,
and a watchdog exits once it goes stale so the restart policy turns a silent
stall into a visibly crash-looping container.
- payout-bot/bot.js: Periodically calls payoutStakersByPage for all
validators in completed eras. Runs every 10 minutes.
- payout-bot/Dockerfile: Node 20 alpine with @pezkuwi/api
- docker-compose.prod.yml: Add payout-bot service with secret mnemonic
Index convictionVoting and referenda pallet data to support PezWallet
governance UI — referendum tracking, casting votes, delegation stats,
and delegator vote propagation.
- Add handleBlock to query live chain state for existing pool members
- Add second GraphQL engine container for Asset Hub schema (port 3001)
- Register block handler in pezkuwi-assethub.yaml