Skip to content

fix(testing): make equivocation head assertions scheme-independent#1189

Merged
tcoratger merged 3 commits into
leanEthereum:mainfrom
leolara:leolara/scheme-independent-equivocation-head
Jul 11, 2026
Merged

fix(testing): make equivocation head assertions scheme-independent#1189
tcoratger merged 3 commits into
leanEthereum:mainfrom
leolara:leolara/scheme-independent-equivocation-head

Conversation

@leolara

@leolara leolara commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Problem

The Production Test Vectors job failed on main (run 28858797181): 3 fork-choice equivocation vectors failed, 551 passed:

test_same_slot_equivocating_attesters_count_once            head_slot = 2, expected 3
test_equivocation_head_independent_of_arrival_order_a_then_b head_slot = 3, expected 2
test_equivocation_head_independent_of_arrival_order_b_then_a head_slot = 3, expected 2

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 test and prod schemes. The 3 vectors hardcoded the winning fork, so they passed under test (what PR CI runs) and failed under prod (what prod-vectors runs, on main only). Same class of bug as #916.

Fix

The vectors now assert the invariant, not the lottery winner:

  • New scheme-independent check canonical_equivocation_head_among: reads each fork's attestation root from the store and asserts the head is the largest-root fork. Mirrors the existing lexicographic_head_among; never pins which fork wins.
  • Rewrote the 3 vectors to use it, dropping the scheme-fragile head_slot/head_root_label and the equivocators' target_slot pins. Given/When/Then docstrings describe the invariant.
  • Docstring on the tiebreak (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

  • The 3 vectors pass under both --scheme=test and --scheme=prod.
  • Full fork-choice tree (123 vectors) passes under both schemes.
  • just check clean.

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.
@leolara leolara marked this pull request as ready for review July 9, 2026 07:20
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.
@tcoratger

Copy link
Copy Markdown
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 ? :)

@leolara

leolara commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

@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 ? :)

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 tcoratger merged commit eca701e into leanEthereum:main Jul 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants