fill fails to generate the #1181 equivocation fixtures at HEAD — fork choice disagrees with the vectors' expected head
At current main (4ca7d27e46b9b978c4f0a9b7e8eb6fd06be8286d), generating the lstar fixture set fails: the three equivocation tests added in #1181 assert a head that the fork-choice implementation does not produce. fill therefore exits non-zero, which blocks generating (and consuming) the full lstar fixture set at HEAD. We hit this integrating gean against HEAD.
Reproduction
uv run fill --clean --fork=lstar --scheme=prod --output=fixtures
E AssertionError: Step 6: head_slot = 2, expected 3
E AssertionError: Step 6: head_slot = 3, expected 2
E AssertionError: Step 6: head_slot = 3, expected 2
=========================== short test summary info ============================
FAILED tests/consensus/lstar/fork_choice/test_equivocation.py::test_same_slot_equivocating_attesters_count_once[fork_Lstar]
FAILED tests/consensus/lstar/fork_choice/test_equivocation.py::test_equivocation_head_independent_of_arrival_order_a_then_b[fork_Lstar]
FAILED tests/consensus/lstar/fork_choice/test_equivocation.py::test_equivocation_head_independent_of_arrival_order_b_then_a[fork_Lstar]
========== 3 failed, 551 passed, 35 deselected ==========
All other 551 tests generate cleanly; only these three fail.
What the failures suggest
The two arrival-order tests are the interesting signal:
..._a_then_b → head_slot = 3 (expected 2)
..._b_then_a → head_slot = 3 (expected 2)
Both deliveries produce the same head (3), so the order-independence property #1181 introduced is holding — the head is a pure function of store contents. But the deterministic result disagrees with the vectors' expected value (3 vs 2), and test_same_slot_equivocating_attesters_count_once disagrees in the other direction (2 vs 3).
That reads like an implementation-vs-vector mismatch introduced with #1181: the equal-slot tie-break resolves to a different branch than the test vectors encode. Either the tie-break direction in the fork-choice code and the expected head in these vectors were computed against different conventions, or one of the two is off.
For reference, test_same_slot_equivocating_attesters_count_once's own docstring states the intent as "the two votes tie on slot, so the larger attestation-data root wins … head is fork_b" — so the intent (larger canonical root wins) is clear; the disagreement is about which concrete head that yields in these fixtures.
Impact
Question
Is this a known issue? Is the intended fix to adjust the tie-break resolution in fork_choice.py, or to regenerate/correct the expected heads in these three vectors?
Happy to provide the full fill log or a minimal repro if useful.
fillfails to generate the #1181 equivocation fixtures at HEAD — fork choice disagrees with the vectors' expected headAt current
main(4ca7d27e46b9b978c4f0a9b7e8eb6fd06be8286d), generating thelstarfixture set fails: the three equivocation tests added in #1181 assert a head that the fork-choice implementation does not produce.filltherefore exits non-zero, which blocks generating (and consuming) the fulllstarfixture set at HEAD. We hit this integrating gean against HEAD.Reproduction
All other 551 tests generate cleanly; only these three fail.
What the failures suggest
The two arrival-order tests are the interesting signal:
..._a_then_b→head_slot = 3(expected2)..._b_then_a→head_slot = 3(expected2)Both deliveries produce the same head (
3), so the order-independence property #1181 introduced is holding — the head is a pure function of store contents. But the deterministic result disagrees with the vectors' expected value (3vs2), andtest_same_slot_equivocating_attesters_count_oncedisagrees in the other direction (2vs3).That reads like an implementation-vs-vector mismatch introduced with #1181: the equal-slot tie-break resolves to a different branch than the test vectors encode. Either the tie-break direction in the fork-choice code and the expected head in these vectors were computed against different conventions, or one of the two is off.
For reference,
test_same_slot_equivocating_attesters_count_once's own docstring states the intent as "the two votes tie on slot, so the larger attestation-data root wins … head is fork_b" — so the intent (larger canonical root wins) is clear; the disagreement is about which concrete head that yields in these fixtures.Impact
fill --fork=lstarcannot produce the full fixture set at HEAD, so downstream clients cannot regenerate/consume thelstarvectors until this is resolved (we worked around it by excludingtest_equivocation.pyto validate the rest).Question
Is this a known issue? Is the intended fix to adjust the tie-break resolution in
fork_choice.py, or to regenerate/correct the expected heads in these three vectors?Happy to provide the full
filllog or a minimal repro if useful.