fix(testing): make equivocation head assertions scheme-independent#1189
Merged
tcoratger merged 3 commits intoJul 11, 2026
Merged
Conversation
The equivocation tiebreak vectors hardcoded the winning fork of leanEthereum#1181's largest-attestation-data-root rule. That root embeds validator XMSS pubkeys, so the winner flips between test and prod schemes; the vectors passed PR CI (test scheme) and failed prod-vectors on main (prod scheme). Same class as leanEthereum#916. Add a scheme-independent canonical_equivocation_head_among check that reads each fork's attestation root from the store and asserts the head is the largest-root fork, mirroring lexicographic_head_among. Rewrite the 3 vectors to use it, note the scheme-dependence on the spec tiebreak, add a CLAUDE.md rule, and gate fork-choice vectors under --scheme=prod in PR CI.
The fill-tests-prod-scheme job was cancelled at its 20-minute timeout on the macOS runner (the fork-choice tree under --scheme=prod takes >20 min in CI). Remove it; the scheme-independence rule in CLAUDE.md and the canonical_equivocation_head_among check remain.
Collaborator
|
@leolara can we reduce the number of line for the new documentation as per doc writer agent rules to keep things lean and facilitate the reading experience ? :) |
Contributor
Author
You are right, we are all learning about how to use these new tools. |
Cut the root-to-pubkey derivations and test guidance an experienced reader already knows. The CLAUDE.md rule keeps the actionable bullets, the check's field docstring matches lexicographic_head_among's brevity, and the spec docstring states only the behavioral property (no test instructions).
tcoratger
approved these changes
Jul 11, 2026
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.
Problem
The
Production Test Vectorsjob failed onmain(run 28858797181): 3 fork-choice equivocation vectors failed, 551 passed:Root cause
PR #1181 breaks an equal-slot equivocation tie toward the fork with the largest attestation-data root. That root embeds the target block root, which embeds the genesis state root, which embeds the validator XMSS public keys — so the winner flips between the
testandprodschemes. The 3 vectors hardcoded the winning fork, so they passed undertest(what PR CI runs) and failed underprod(whatprod-vectorsruns, onmainonly). Same class of bug as #916.Fix
The vectors now assert the invariant, not the lottery winner:
canonical_equivocation_head_among: reads each fork's attestation root from the store and asserts the head is the largest-root fork. Mirrors the existinglexicographic_head_among; never pins which fork wins.head_slot/head_root_labeland the equivocators'target_slotpins. Given/When/Then docstrings describe the invariant.fork_choice.py) flags that the winner's identity is key-material-dependent.CLAUDE.md: new rule — fork-choice head assertions must be scheme-independent.No consensus-rule change; the tiebreak behavior is unchanged.
Testing
--scheme=testand--scheme=prod.just checkclean.