Summary
charon exit sign --all silently skips validators that have a registered deposit but are not yet active on the beacon chain. Because Ethereum has an activation queue, such validators can activate after the cluster has exited and operators have shut down their nodes, causing missed duties and penalties for validators the operators believed were fully exited.
What happened
A cluster ran charon exit sign --all to exit all its validators and then shut down. Some validators had deposits registered on-chain but were not yet activated — they had no validator index yet, so no exit could be signed for them, and --all skipped them without warning. Ethereum's activation queue later processed those deposits and the validators became active — after the exits, and after operators had shut their nodes down — so they accrued duties nobody performed, resulting in penalties.
Root cause
signAllValidatorsExits (cmd/exit_sign.go) queries the beacon node only for pending_queued / active_ongoing. Any cluster validator the beacon does not return is counted as inactive and skipped with no warning. Two categories fall through: validators with no index yet (deposit registered but still in the beacon pending_deposits queue — no index exists to sign against), and pending_initialized validators (they have an index and could be pre-signed, but are excluded by the state filter). The operator is left believing every validator was exited.
Proposed fix
- Warn when a cluster validator has a deposit in the beacon
pending_deposits queue but no index yet, so the operator re-runs once it has one (top-ups to already-indexed validators excluded).
- Pre-sign exits for
pending_initialized validators — they have an index, and the exit is broadcastable once they activate (harmlessly skipped by broadcast until then).
Summary
charon exit sign --allsilently skips validators that have a registered deposit but are not yet active on the beacon chain. Because Ethereum has an activation queue, such validators can activate after the cluster has exited and operators have shut down their nodes, causing missed duties and penalties for validators the operators believed were fully exited.What happened
A cluster ran
charon exit sign --allto exit all its validators and then shut down. Some validators had deposits registered on-chain but were not yet activated — they had no validator index yet, so no exit could be signed for them, and--allskipped them without warning. Ethereum's activation queue later processed those deposits and the validators became active — after the exits, and after operators had shut their nodes down — so they accrued duties nobody performed, resulting in penalties.Root cause
signAllValidatorsExits(cmd/exit_sign.go) queries the beacon node only forpending_queued/active_ongoing. Any cluster validator the beacon does not return is counted asinactiveand skipped with no warning. Two categories fall through: validators with no index yet (deposit registered but still in the beaconpending_depositsqueue — no index exists to sign against), andpending_initializedvalidators (they have an index and could be pre-signed, but are excluded by the state filter). The operator is left believing every validator was exited.Proposed fix
pending_depositsqueue but no index yet, so the operator re-runs once it has one (top-ups to already-indexed validators excluded).pending_initializedvalidators — they have an index, and the exit is broadcastable once they activate (harmlessly skipped bybroadcastuntil then).