feat(validator): refuse to sign a slot a key already signed - #1204
Open
adust09 wants to merge 1 commit into
Open
feat(validator): refuse to sign a slot a key already signed#1204adust09 wants to merge 1 commit into
adust09 wants to merge 1 commit into
Conversation
The signature scheme is a stateful one-time signature indexed by slot, and `sign` states that a key must never sign two different messages for the same slot without enforcing it. The only thing upholding that was `_attested_slots`, an in-memory set pruned after four slots, with no per-slot guard at all on the proposal path. A crash-restart inside a slot, a backward clock step, or a restore from backup therefore re-ran the duty against a possibly different head and signed a second message under the same one-time key, which opens two positions in the same hash chains and lets a third signature be forged. Record the highest slot each validator key has signed and check it at the signing boundary. The record lives in the node database, so it survives a restart; without a database it stays process-local and `run` warns that the protection is not durable. Attestation and proposal keys are tracked separately, so signing both in one slot stays legal. The claim commits before the signature so an interruption in between forfeits the duty, not the key. `_attested_slots` stays as the duty loop's dedup optimization; the new record is the safety guarantee. Signing records are never pruned: dropping a row re-opens the key it protects. Closes leanEthereum#1203
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1203.
sign()requires that a key never sign two different messages for one slot, but only an in-memory set upheld it — and the proposal path had no per-slot guard at all. A crash-restart, a backward clock step, or a restore re-ran the duty against a possibly different head and signed twice under the same one-time key.Records the highest slot each key has signed and refuses
slot <= last_signed_slotat the signing boundary.signing_recordstable keyed by(validator_index, key_role), never pruned.run()warns._attested_slotsstays as the duty loop's dedup.Concurrent nodes sharing a key keep separate records, so exclusive key-store access remains an operational requirement.
17 new tests, including a restart scenario: sign slot 1, reopen the database, replacement service refused. 2961 passed, coverage 91.79%.