Expand description
Startup self-check: is the local iroh key the one bound on-chain? (#1034)
SlashJudge._checkRegistered resolves an accused node through
CapacityBond.nodeIdOf, so slashability follows the binding, not the key
the daemon happens to serve under. A node whose node.secret was replaced
without a matching bindNodeId therefore keeps serving and keeps getting
paid while its bond is unreachable — it is unslashable. Nothing else in the
runtime notices: the node is healthy, its channels settle, and its peers
simply stop routing to an id no longer in the staker set, which reads like
ordinary churn.
That is the gap this check closes, and the reason it exists on the daemon at
all rather than only in decdn node rotate-key. The command is written so
the state is unreachable through it — the key file is committed only after
the bind confirms — but the state is reachable around it, by an operator
copying a key file, restoring the wrong backup, or running decdn key-gen --force in a data dir that was already registered.
§Advisory, deliberately
The result never blocks startup. A daemon that refused to boot on a
mismatch would be brickable by a transient RPC failure, and — worse —
unable to run during the very window an operator needs it up to diagnose
and repair the binding. So the check reports: a WARN line at bring-up and
a field on admin_v1_health, both naming the repair.
§Sampled once
The binding changes only by an explicit operator transaction, so this runs
once during bring-up rather than per health poll — admin_v1_health is on
the readiness path, and putting a chain round trip behind it would make
every probe pay for a value that almost never moves.
Structs§
- Binding
Report - Outcome of the bring-up binding check, as carried into
AdminState.
Functions§
- check
- Read
CapacityBond.addressToNodeId(operator)and compare it with the key the daemon is about to serve under, logging the outcome. - classify
- Classify a binding read. Pure so every arm is reachable from a unit test —
the chain read that produces
boundcannot be steered to these values from a fixture without deploying a contract per case.