Skip to content

Commit 46a14d6

Browse files
authored
Introduce compute_shuffling_lookahead_start_slot helper (#5602)
1 parent 09c77a4 commit 46a14d6

4 files changed

Lines changed: 46 additions & 54 deletions

File tree

specs/gloas/fork-choice.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- [Modified `get_latest_message_epoch`](#modified-get_latest_message_epoch)
4242
- [New `verify_execution_payload_envelope`](#new-verify_execution_payload_envelope)
4343
- [New `is_valid_dependent_root`](#new-is_valid_dependent_root)
44+
- [New `compute_shuffling_lookahead_start_slot`](#new-compute_shuffling_lookahead_start_slot)
4445
- [Modified `get_attestation_due_ms`](#modified-get_attestation_due_ms)
4546
- [Modified `get_aggregate_due_ms`](#modified-get_aggregate_due_ms)
4647
- [Modified `get_sync_message_due_ms`](#modified-get_sync_message_due_ms)
@@ -716,6 +717,15 @@ def is_valid_dependent_root(store: Store, root: Root, dependent_slot: Slot) -> b
716717
return False
717718
```
718719

720+
### New `compute_shuffling_lookahead_start_slot`
721+
722+
```python
723+
def compute_shuffling_lookahead_start_slot(epoch: Epoch) -> Slot:
724+
if epoch <= MIN_SEED_LOOKAHEAD:
725+
return GENESIS_SLOT
726+
return compute_start_slot_at_epoch(epoch - MIN_SEED_LOOKAHEAD)
727+
```
728+
719729
### Modified `get_attestation_due_ms`
720730

721731
```python

specs/gloas/p2p-interface.md

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
- [New `is_past_slot`](#new-is_past_slot)
2727
- [New `is_gas_limit_target_compatible`](#new-is_gas_limit_target_compatible)
2828
- [New `is_bid_compatible_with_head`](#new-is_bid_compatible_with_head)
29-
- [New `compute_shuffling_dependent_epoch`](#new-compute_shuffling_dependent_epoch)
3029
- [New `verify_attestation_payload_status`](#new-verify_attestation_payload_status)
3130
- [New `verify_block_body_operation_limits`](#new-verify_block_body_operation_limits)
3231
- [New `verify_execution_requests_limits`](#new-verify_execution_requests_limits)
@@ -380,19 +379,6 @@ def is_bid_compatible_with_head(store: Store, bid: ExecutionPayloadBid) -> bool:
380379
return builds_on_parent_payload
381380
```
382381

383-
### New `compute_shuffling_dependent_epoch`
384-
385-
```python
386-
def compute_shuffling_dependent_epoch(epoch: Epoch) -> Epoch:
387-
"""
388-
Return the epoch that determines the shuffling for the given ``epoch``.
389-
For the first ``MIN_SEED_LOOKAHEAD`` epochs, this is ``GENESIS_EPOCH``.
390-
"""
391-
if epoch <= MIN_SEED_LOOKAHEAD:
392-
return GENESIS_EPOCH
393-
return epoch - MIN_SEED_LOOKAHEAD
394-
```
395-
396382
### New `verify_attestation_payload_status`
397383

398384
```python
@@ -1093,9 +1079,8 @@ def validate_proposer_preferences_gossip(
10931079
raise GossipIgnore("proposal slot has already started")
10941080

10951081
# [IGNORE] The proposer for the proposal slot is known
1096-
lookahead_epoch = compute_shuffling_dependent_epoch(proposal_epoch)
1097-
lookahead_epoch_start_slot = compute_start_slot_at_epoch(lookahead_epoch)
1098-
if is_future_slot(store, lookahead_epoch_start_slot, current_time_ms):
1082+
lookahead_start_slot = compute_shuffling_lookahead_start_slot(proposal_epoch)
1083+
if is_future_slot(store, lookahead_start_slot, current_time_ms):
10991084
raise GossipIgnore("proposer for the proposal slot is not yet known")
11001085

11011086
# [IGNORE] The dependent block has been seen (via gossip or non-gossip sources)
@@ -1117,16 +1102,16 @@ def validate_proposer_preferences_gossip(
11171102
raise GossipIgnore("dependent block is not a possible dependent block")
11181103

11191104
# [REJECT] The validator is the proposer for the given slot in the proposer lookahead
1120-
lookahead_state = store.block_states[preferences.dependent_root].copy()
1121-
if lookahead_state.slot < lookahead_epoch_start_slot:
1122-
process_slots(lookahead_state, lookahead_epoch_start_slot)
1123-
lookahead_index = preferences.proposal_slot - lookahead_epoch_start_slot
1124-
if lookahead_state.proposer_lookahead[lookahead_index] != preferences.validator_index:
1105+
state = store.block_states[preferences.dependent_root].copy()
1106+
if state.slot < lookahead_start_slot:
1107+
process_slots(state, lookahead_start_slot)
1108+
lookahead_index = preferences.proposal_slot - lookahead_start_slot
1109+
if state.proposer_lookahead[lookahead_index] != preferences.validator_index:
11251110
raise GossipReject("validator is not the proposer for the given slot")
11261111

11271112
# [REJECT] The signature is valid
1128-
validator = lookahead_state.validators[preferences.validator_index]
1129-
domain = get_domain(lookahead_state, DOMAIN_PROPOSER_PREFERENCES, proposal_epoch)
1113+
validator = state.validators[preferences.validator_index]
1114+
domain = get_domain(state, DOMAIN_PROPOSER_PREFERENCES, proposal_epoch)
11301115
signing_root = compute_signing_root(preferences, domain)
11311116
if not bls.Verify(validator.pubkey, signing_root, signed_proposer_preferences.signature):
11321117
raise GossipReject("invalid proposer preferences signature")

specs/heze/fork-choice.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,15 @@ def on_inclusion_list(store: Store, signed_inclusion_list: SignedInclusionList)
293293
assert is_valid_dependent_root(store, inclusion_list.dependent_root, dependent_slot)
294294

295295
# Verify the validator is in the inclusion list committee
296-
dependent_state = store.block_states[inclusion_list.dependent_root].copy()
297-
if dependent_state.slot < inclusion_list.slot:
298-
process_slots(dependent_state, inclusion_list.slot)
299-
committee = get_inclusion_list_committee(dependent_state, inclusion_list.slot)
296+
state = store.block_states[inclusion_list.dependent_root].copy()
297+
lookahead_start_slot = compute_shuffling_lookahead_start_slot(epoch)
298+
if state.slot < lookahead_start_slot:
299+
process_slots(state, lookahead_start_slot)
300+
committee = get_inclusion_list_committee(state, inclusion_list.slot)
300301
assert inclusion_list.validator_index in committee
301302

302303
# Verify the signature
303-
assert is_valid_inclusion_list_signature(dependent_state, signed_inclusion_list)
304+
assert is_valid_inclusion_list_signature(state, signed_inclusion_list)
304305

305306
# The inclusion list is timely if it arrives in its slot before the deadline
306307
seconds_since_genesis = store.time - store.genesis_time

tests/core/pyspec/eth_consensus_specs/test/gloas/networking/test_gossip_proposer_preferences.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -443,28 +443,28 @@ def setup_lookahead_boundary_preferences(spec, state):
443443
lookahead lower bound for the proposal slot.
444444
"""
445445
lookahead_epoch = spec.Epoch(spec.MIN_SEED_LOOKAHEAD + 3)
446-
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
447-
store, blocks = setup_store_with_advanced_state(spec, state, lookahead_epoch_start_slot)
446+
lookahead_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
447+
store, blocks = setup_store_with_advanced_state(spec, state, lookahead_start_slot)
448448

449449
# The dependent block is the last one before the epoch transition.
450450
dependent_root = blocks[-2].message.hash_tree_root()
451451
dependent_state = store.block_states[dependent_root]
452452
assert spec.get_current_epoch(dependent_state) == spec.Epoch(lookahead_epoch - 1)
453453

454454
lookahead_state = dependent_state.copy()
455-
spec.process_slots(lookahead_state, lookahead_epoch_start_slot)
455+
spec.process_slots(lookahead_state, lookahead_start_slot)
456456
proposal_slot = spec.compute_start_slot_at_epoch(
457457
spec.Epoch(lookahead_epoch + spec.MIN_SEED_LOOKAHEAD)
458458
)
459-
lookahead_index = proposal_slot - lookahead_epoch_start_slot
459+
lookahead_index = proposal_slot - lookahead_start_slot
460460
signed_prefs = build_signed_proposer_preferences(
461461
spec,
462462
lookahead_state,
463463
proposal_slot=proposal_slot,
464464
validator_index=lookahead_state.proposer_lookahead[lookahead_index],
465465
dependent_root=dependent_root,
466466
)
467-
return store, blocks, signed_prefs, lookahead_epoch_start_slot
467+
return store, blocks, signed_prefs, lookahead_start_slot
468468

469469

470470
@with_gloas_and_later
@@ -478,7 +478,7 @@ def test_gossip_proposer_preferences__ignore_outside_lookahead_disparity(spec, s
478478
anchor_state = state.copy()
479479
yield "topic", "meta", "proposer_preferences"
480480

481-
store, blocks, signed_prefs, lookahead_epoch_start_slot = setup_lookahead_boundary_preferences(
481+
store, blocks, signed_prefs, lookahead_start_slot = setup_lookahead_boundary_preferences(
482482
spec, state
483483
)
484484

@@ -489,7 +489,7 @@ def test_gossip_proposer_preferences__ignore_outside_lookahead_disparity(spec, s
489489
yield get_filename(signed_prefs), signed_prefs
490490

491491
time_ms = (
492-
spec.compute_time_at_slot_ms(store, lookahead_epoch_start_slot)
492+
spec.compute_time_at_slot_ms(store, lookahead_start_slot)
493493
- spec.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY
494494
- 1
495495
)
@@ -529,7 +529,7 @@ def test_gossip_proposer_preferences__valid_at_lookahead_disparity_edge(spec, st
529529
anchor_state = state.copy()
530530
yield "topic", "meta", "proposer_preferences"
531531

532-
store, blocks, signed_prefs, lookahead_epoch_start_slot = setup_lookahead_boundary_preferences(
532+
store, blocks, signed_prefs, lookahead_start_slot = setup_lookahead_boundary_preferences(
533533
spec, state
534534
)
535535

@@ -540,7 +540,7 @@ def test_gossip_proposer_preferences__valid_at_lookahead_disparity_edge(spec, st
540540
yield get_filename(signed_prefs), signed_prefs
541541

542542
time_ms = (
543-
spec.compute_time_at_slot_ms(store, lookahead_epoch_start_slot)
543+
spec.compute_time_at_slot_ms(store, lookahead_start_slot)
544544
- spec.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY
545545
)
546546
yield "current_time_ms", "meta", int(time_ms)
@@ -1020,16 +1020,13 @@ def test_gossip_proposer_preferences__reject_dependent_root_at_lookahead_epoch_s
10201020

10211021
proposal_slot, validator_index = find_upcoming_proposal_slot(spec, state)
10221022
proposal_epoch = spec.compute_epoch_at_slot(proposal_slot)
1023-
lookahead_epoch = spec.Epoch(proposal_epoch - spec.MIN_SEED_LOOKAHEAD)
1024-
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
1023+
lookahead_start_slot = spec.compute_shuffling_lookahead_start_slot(proposal_epoch)
10251024

10261025
boundary_block = next(
1027-
signed_block
1028-
for signed_block in blocks
1029-
if signed_block.message.slot == lookahead_epoch_start_slot
1026+
signed_block for signed_block in blocks if signed_block.message.slot == lookahead_start_slot
10301027
)
10311028
dependent_root = boundary_block.message.hash_tree_root()
1032-
assert store.block_states[dependent_root].slot == lookahead_epoch_start_slot
1029+
assert store.block_states[dependent_root].slot == lookahead_start_slot
10331030

10341031
# Sign valid preferences for the upcoming slot's true proposer, but point
10351032
# dependent_root at the first block whose stored state is exactly at the
@@ -1096,8 +1093,8 @@ def test_gossip_proposer_preferences__ignore_dependent_root_not_possible(spec, s
10961093
# superseded on the only branch.
10971094
proposal_slot, validator_index = find_upcoming_proposal_slot(spec, state)
10981095
proposal_epoch = spec.compute_epoch_at_slot(proposal_slot)
1099-
lookahead_epoch = spec.Epoch(proposal_epoch - spec.MIN_SEED_LOOKAHEAD)
1100-
superseded_slot = spec.Slot(spec.compute_start_slot_at_epoch(lookahead_epoch) - 2)
1096+
lookahead_start_slot = spec.compute_shuffling_lookahead_start_slot(proposal_epoch)
1097+
superseded_slot = spec.Slot(lookahead_start_slot - 2)
11011098
signed_prefs = build_signed_proposer_preferences(
11021099
spec,
11031100
state,
@@ -1150,13 +1147,12 @@ def test_gossip_proposer_preferences__valid_dependent_root_on_fork(spec, state):
11501147

11511148
proposal_slot, validator_index = find_upcoming_proposal_slot(spec, state)
11521149
proposal_epoch = spec.compute_epoch_at_slot(proposal_slot)
1153-
lookahead_epoch = spec.Epoch(proposal_epoch - spec.MIN_SEED_LOOKAHEAD)
1154-
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
1150+
lookahead_start_slot = spec.compute_shuffling_lookahead_start_slot(proposal_epoch)
11551151

11561152
# Fork off two slots before the lookahead epoch start and build a branch
11571153
# whose first block stays before the epoch start and whose second block
11581154
# crosses it.
1159-
fork_parent_root = spec.get_block_root_at_slot(state, spec.Slot(lookahead_epoch_start_slot - 2))
1155+
fork_parent_root = spec.get_block_root_at_slot(state, spec.Slot(lookahead_start_slot - 2))
11601156
fork_state = store.block_states[fork_parent_root].copy()
11611157
fork_blocks = []
11621158
for _ in range(2):
@@ -1168,8 +1164,8 @@ def test_gossip_proposer_preferences__valid_dependent_root_on_fork(spec, state):
11681164
store.block_states[block_root] = fork_state.copy()
11691165
fork_blocks.append(signed_fork_block)
11701166
dependent_root = fork_blocks[0].message.hash_tree_root()
1171-
assert store.blocks[dependent_root].slot == lookahead_epoch_start_slot - 1
1172-
assert fork_blocks[1].message.slot == lookahead_epoch_start_slot
1167+
assert store.blocks[dependent_root].slot == lookahead_start_slot - 1
1168+
assert fork_blocks[1].message.slot == lookahead_start_slot
11731169

11741170
yield "state", anchor_state
11751171
seen = get_seen(spec)
@@ -1222,7 +1218,7 @@ def test_gossip_proposer_preferences__valid_dependent_root_across_empty_epochs(s
12221218
yield "topic", "meta", "proposer_preferences"
12231219

12241220
current_epoch = spec.Epoch(spec.MIN_SEED_LOOKAHEAD + 2)
1225-
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(current_epoch)
1221+
lookahead_start_slot = spec.compute_start_slot_at_epoch(current_epoch)
12261222

12271223
# Build the canonical chain to the slot before two fully empty epochs.
12281224
first_empty_epoch = spec.Epoch(current_epoch - 2)
@@ -1232,7 +1228,7 @@ def test_gossip_proposer_preferences__valid_dependent_root_across_empty_epochs(s
12321228
dependent_state = state.copy()
12331229

12341230
# Skip both epochs, then import the first block at the lookahead boundary.
1235-
boundary_block = build_empty_block(spec, state, slot=lookahead_epoch_start_slot)
1231+
boundary_block = build_empty_block(spec, state, slot=lookahead_start_slot)
12361232
signed_boundary_block = state_transition_and_sign_block(spec, state, boundary_block)
12371233
boundary_root = signed_boundary_block.message.hash_tree_root()
12381234
store.blocks[boundary_root] = signed_boundary_block.message
@@ -1245,7 +1241,7 @@ def test_gossip_proposer_preferences__valid_dependent_root_across_empty_epochs(s
12451241
assert spec.get_shuffling_dependent_root(store, boundary_root, proposal_epoch) == dependent_root
12461242

12471243
lookahead_state = dependent_state.copy()
1248-
spec.process_slots(lookahead_state, lookahead_epoch_start_slot)
1244+
spec.process_slots(lookahead_state, lookahead_start_slot)
12491245
# Pick a slot that distinguishes the advanced lookahead from the stale
12501246
# lookahead in the dependent block's post-state.
12511247
for slot_offset in range(spec.SLOTS_PER_EPOCH):

0 commit comments

Comments
 (0)