Skip to content

Test proposer lookahead initialization uses active validator set at fork #4413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

linoscope
Copy link
Contributor

@linoscope linoscope commented Jun 27, 2025

Add a spec-test that checks whether proposer lookahead uses the correct active validator set at fork transition.
Had this test existed earlier, it would have detected the Prysm bug fixed by @potuz in OffchainLabs/prysm#15450.

Closes #4412 .

Validation note

To verify that the new test catches the Prysm issue, I temporarily replaced the reference implementation of initialize_proposer_lookahead with a buggy variant that mimics the original Prysm logic:

# Correct implementation (passes the new test)
def initialize_proposer_lookahead(
    state: electra.BeaconState,
) -> Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]:
    """
    Return proposer indices for the entire lookahead window starting at the current epoch.
    Used to initialise ``proposer_lookahead`` at genesis and after forks.
    """
    current_epoch = get_current_epoch(state)
    lookahead: list[ValidatorIndex] = []
    for i in range(MIN_SEED_LOOKAHEAD + 1):
        lookahead.extend(get_beacon_proposer_indices(state, Epoch(current_epoch + i)))
    return lookahead
    
 # Bug-replicating implementation (should fail the new test)
def initialize_proposer_lookahead(
    state: electra.BeaconState,
) -> Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]:
    """
    BUGGY: Re-uses the pre-fork active-validator set.
    """
    current_epoch = get_current_epoch(state)
    lookahead: list[ValidatorIndex] = []
    indices = get_active_validator_indices(state, Epoch(current_epoch))  # BUG: stale set
    for i in range(MIN_SEED_LOOKAHEAD + 1):
        seed = get_seed(state, Epoch(current_epoch + i), DOMAIN_BEACON_PROPOSER)
        lookahead.extend(
            compute_proposer_indices(state, Epoch(current_epoch + i), seed, indices)
        )
    return lookahead

Running the suite with the buggy version causes
test_proposer_lookahead_init_at_fork_only_contains_active_validators to fail, confirming that the new test detects the bug.

@linoscope linoscope changed the title EIP-7917: Add tests for validator exit at fork EIP-7917: Test proposer lookahead initialization uses the correct active validator set at fork Jun 27, 2025
@linoscope linoscope force-pushed the eip-7917-add-tests-for-validator-exit-at-fork branch from bbd514b to e6355ba Compare June 27, 2025 20:00
Copy link
Member

@jtraglia jtraglia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, nice and simple. Thank you!

@jtraglia jtraglia added the testing CI, actions, tests label Jun 27, 2025
@jtraglia jtraglia changed the title EIP-7917: Test proposer lookahead initialization uses the correct active validator set at fork Test proposer lookahead initialization uses active validator set at fork Jun 28, 2025
@jtraglia jtraglia merged commit 50e2cc5 into ethereum:dev Jun 28, 2025
12 checks passed
@jtraglia
Copy link
Member

Follow up. I can confirm that Prysm (dev branch) currently fails this test while all other clients pass it 😄

image

@linoscope
Copy link
Contributor Author

Follow up. I can confirm that Prysm (dev branch) currently fails this test while all other clients pass it 😄

Cool to hear, thanks! That confirms that the test properly detects the bug & that other clients don't have the same bug 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
testing CI, actions, tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add test to check proposer lookahead uses correct active validator set at fork initialization
2 participants