Skip to content

EIP-7917: Deterministic proposer lookahead #4190

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

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e73b5d8
EIP-XXXX Stabilize next epoch proposer lookahead
linoscope Mar 23, 2025
fb3cd63
EIP-XXXX add simple happy case tests
linoscope Mar 23, 2025
3fbe39c
fixup: Code clean up
linoscope Mar 24, 2025
0a37fe7
fixup: Target correct fork
linoscope Mar 24, 2025
a4dd9eb
Merge branch 'dev' into stabalize-next-epoch-lookahead
jtraglia Mar 24, 2025
9b82cb4
Clean up comment
linoscope Mar 25, 2025
7485399
refactor based on review comments
linoscope Mar 25, 2025
6a1d923
fix fork check in genesis helper
linoscope Mar 25, 2025
8fb1a58
improve comments
linoscope Mar 25, 2025
208f368
fix off-by-one error
linoscope Mar 25, 2025
af1892b
fix bug in seed calculation
linoscope Mar 26, 2025
53df021
add proper EIP number (EIP7917)
linoscope Mar 26, 2025
94d9dde
fix lint errors
linoscope Mar 27, 2025
83daa1e
add test to check lookahead consistency before/after Fulu fork
linoscope Mar 29, 2025
b1b0144
add tests for lookahead changes due to EB changes
linoscope Apr 1, 2025
9610b02
fix test folder
linoscope Apr 4, 2025
898432d
fix import
linoscope Apr 4, 2025
0414e6c
fix imports
linoscope Apr 7, 2025
78b3810
add generator EIP-7917 tests
linoscope Apr 7, 2025
291bed7
Merge branch 'dev' into stabalize-next-epoch-lookahead
jtraglia Apr 7, 2025
a54040e
Run make lint
jtraglia Apr 7, 2025
cede1ae
better yielding of vectors
linoscope Apr 8, 2025
3c9cf75
move helper and fix type
linoscope Apr 17, 2025
ec0243d
Merge branch 'dev' into stabalize-next-epoch-lookahead
jtraglia Apr 21, 2025
835df3d
Run make lint
jtraglia Apr 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions specs/electra/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
- [New `has_execution_withdrawal_credential`](#new-has_execution_withdrawal_credential)
- [Modified `is_fully_withdrawable_validator`](#modified-is_fully_withdrawable_validator)
- [Modified `is_partially_withdrawable_validator`](#modified-is_partially_withdrawable_validator)
- [Modified `get_beacon_proposer_index`](#modified-get_beacon_proposer_index)
- [New `compute_proposer_indices`](#new-compute_proposer_indices)
- [New `compute_proposer_lookahead`](#new-compute_proposer_lookahead)
- [Misc](#misc-1)
- [New `get_committee_indices`](#new-get_committee_indices)
- [New `get_max_effective_balance`](#new-get_max_effective_balance)
Expand All @@ -76,6 +79,7 @@
- [New `process_pending_deposits`](#new-process_pending_deposits)
- [New `process_pending_consolidations`](#new-process_pending_consolidations)
- [Modified `process_effective_balance_updates`](#modified-process_effective_balance_updates)
- [New `process_proposer_lookahead`](#new-process_proposer_lookahead)
- [Execution engine](#execution-engine)
- [Request data](#request-data)
- [Modified `NewPayloadRequest`](#modified-newpayloadrequest)
Expand Down Expand Up @@ -420,6 +424,7 @@ class BeaconState(Container):
# [New in Electra:EIP7251]
pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT]
pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] # [New in Electra:EIP7251]
proposer_lookahead: List[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH] # [New in Electra:EIPXXXX]
```

## Helper functions
Expand Down Expand Up @@ -529,6 +534,49 @@ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) ->
)
```

#### Modified `get_beacon_proposer_index`

*Note*: The function `get_beacon_proposer_index` is modified to use the pre-calculated `current_proposer_lookahead` instead of calculating it on-demand.

```python
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
"""
Return the beacon proposer index at the current slot.
"""
slot_offset = state.slot - compute_start_slot_at_epoch(get_current_epoch(state))
return state.proposer_lookahead[slot_offset]
```
#### New `compute_proposer_indices`

```python
def compute_proposer_indices(state: BeaconState, epoch: Epoch) -> List[ValidatorIndex, SLOTS_PER_EPOCH]:
"""
Return the proposer indices for the given ``epoch``.
"""
proposer_indices = []
indices = get_active_validator_indices(state, epoch)
start_slot = compute_start_slot_at_epoch(epoch)
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + uint_to_bytes(Slot(slot)))
proposer_indices.append(compute_proposer_index(state, indices, seed))
return proposer_indices
```

#### New `compute_proposer_lookahead`

```python
def compute_proposer_lookahead(state: BeaconState) -> List[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]:
"""
Return the proposer indices for the full available lookahead starting from current epoch.
"""
current_epoch = get_current_epoch(state)
lookahead = []
for i in range(MIN_SEED_LOOKAHEAD + 1):
proposer_indices = compute_proposer_indices(state, Epoch(current_epoch + i))
lookahead.extend(proposer_indices)
return lookahead
```

### Misc

#### New `get_committee_indices`
Expand Down Expand Up @@ -813,6 +861,7 @@ def process_epoch(state: BeaconState) -> None:
process_historical_summaries_update(state)
process_participation_flag_updates(state)
process_sync_committee_updates(state)
process_proposer_lookahead(state) # [New in Electra:EIPXXXX]
```

#### Modified `process_registry_updates`
Expand Down Expand Up @@ -1002,6 +1051,18 @@ def process_effective_balance_updates(state: BeaconState) -> None:
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, max_effective_balance)
```

#### New `process_proposer_lookahead`

```python
def process_proposer_lookahead(state: BeaconState) -> None:
last_epoch_start = len(state.proposer_lookahead) - SLOTS_PER_EPOCH
# Shift out proposers in the first epoch.
state.proposer_lookahead[0:last_epoch_start] = state.proposer_lookahead[SLOTS_PER_EPOCH:]
# Fill in the last epoch with new proposer indices.
last_epoch_proposers = compute_proposer_indices(state, Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD))
state.proposer_lookahead[last_epoch_start:] = last_epoch_proposers
```

### Execution engine

#### Request data
Expand Down
2 changes: 2 additions & 0 deletions specs/electra/fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
pending_deposits=[],
pending_partial_withdrawals=[],
pending_consolidations=[],
# [New in Electra:EIPXXXX]
proposer_lookahead=compute_proposer_lookahead(pre)
)

post.exit_balance_to_consume = get_activation_exit_churn_limit(post)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from eth2spec.test.context import spec_state_test, with_electra_and_later
from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with
from eth2spec.test.helpers.state import next_epoch


@with_electra_and_later
@spec_state_test
def test_next_epoch_proposer_lookahead_shifted_to_front(spec, state):
"""Test that the next epoch proposer lookahead is "shifted" to the front at epoch transition."""
# Transition few epochs to pass the MIN_SEED_LOOKAHEAD
next_epoch(spec, state)
next_epoch(spec, state)
# Get initial lookahead
initial_lookahead = state.proposer_lookahead.copy()

# Run epoch processing
yield from run_epoch_processing_with(spec, state, 'process_proposer_lookahead')

# Verify lookahead was shifted correctly
assert state.proposer_lookahead[:spec.SLOTS_PER_EPOCH] == initial_lookahead[spec.SLOTS_PER_EPOCH:]


@with_electra_and_later
@spec_state_test
def test_proposer_lookahead_in_state_matches_computed_lookahead(spec, state):
"""Test that the proposer lookahead in the state matches the lookahead computed on the fly."""
# Transition few epochs to pass the MIN_SEED_LOOKAHEAD
next_epoch(spec, state)
next_epoch(spec, state)

# Run epoch processing
yield from run_epoch_processing_with(spec, state, 'process_proposer_lookahead')

# Verify lookahead in state matches the lookahead computed on the fly
computed_lookahead = spec.compute_proposer_lookahead(state)
assert state.proposer_lookahead == computed_lookahead
2 changes: 2 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ def create_genesis_state(spec, validator_balances, activation_threshold):

if is_post_electra(spec):
state.deposit_requests_start_index = spec.UNSET_DEPOSIT_REQUESTS_START_INDEX
# Initialize proposer lookahead list
state.proposer_lookahead = spec.compute_proposer_lookahead(state)

if is_post_eip7441(spec):
vc = len(state.validators)
Expand Down
Loading