Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions specs/gloas/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
- [Modified `get_latest_message_epoch`](#modified-get_latest_message_epoch)
- [New `verify_execution_payload_envelope`](#new-verify_execution_payload_envelope)
- [New `is_valid_dependent_root`](#new-is_valid_dependent_root)
- [New `compute_shuffling_lookahead_start_slot`](#new-compute_shuffling_lookahead_start_slot)
- [Modified `get_attestation_due_ms`](#modified-get_attestation_due_ms)
- [Modified `get_aggregate_due_ms`](#modified-get_aggregate_due_ms)
- [Modified `get_sync_message_due_ms`](#modified-get_sync_message_due_ms)
Expand Down Expand Up @@ -716,6 +717,15 @@ def is_valid_dependent_root(store: Store, root: Root, dependent_slot: Slot) -> b
return False
```

### New `compute_shuffling_lookahead_start_slot`

```python
def compute_shuffling_lookahead_start_slot(epoch: Epoch) -> Slot:
if epoch <= MIN_SEED_LOOKAHEAD:
return GENESIS_SLOT
return compute_start_slot_at_epoch(epoch - MIN_SEED_LOOKAHEAD)
```

### Modified `get_attestation_due_ms`

```python
Expand Down
33 changes: 9 additions & 24 deletions specs/gloas/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
- [New `is_past_slot`](#new-is_past_slot)
- [New `is_gas_limit_target_compatible`](#new-is_gas_limit_target_compatible)
- [New `is_bid_compatible_with_head`](#new-is_bid_compatible_with_head)
- [New `compute_shuffling_dependent_epoch`](#new-compute_shuffling_dependent_epoch)
- [New `verify_attestation_payload_status`](#new-verify_attestation_payload_status)
- [New `verify_block_body_operation_limits`](#new-verify_block_body_operation_limits)
- [New `verify_execution_requests_limits`](#new-verify_execution_requests_limits)
Expand Down Expand Up @@ -380,19 +379,6 @@ def is_bid_compatible_with_head(store: Store, bid: ExecutionPayloadBid) -> bool:
return builds_on_parent_payload
```

### New `compute_shuffling_dependent_epoch`

```python
def compute_shuffling_dependent_epoch(epoch: Epoch) -> Epoch:
"""
Return the epoch that determines the shuffling for the given ``epoch``.
For the first ``MIN_SEED_LOOKAHEAD`` epochs, this is ``GENESIS_EPOCH``.
"""
if epoch <= MIN_SEED_LOOKAHEAD:
return GENESIS_EPOCH
return epoch - MIN_SEED_LOOKAHEAD
```

### New `verify_attestation_payload_status`

```python
Expand Down Expand Up @@ -1093,9 +1079,8 @@ def validate_proposer_preferences_gossip(
raise GossipIgnore("proposal slot has already started")

# [IGNORE] The proposer for the proposal slot is known
lookahead_epoch = compute_shuffling_dependent_epoch(proposal_epoch)
lookahead_epoch_start_slot = compute_start_slot_at_epoch(lookahead_epoch)
if is_future_slot(store, lookahead_epoch_start_slot, current_time_ms):
lookahead_start_slot = compute_shuffling_lookahead_start_slot(proposal_epoch)
if is_future_slot(store, lookahead_start_slot, current_time_ms):
raise GossipIgnore("proposer for the proposal slot is not yet known")

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

# [REJECT] The validator is the proposer for the given slot in the proposer lookahead
lookahead_state = store.block_states[preferences.dependent_root].copy()
if lookahead_state.slot < lookahead_epoch_start_slot:
process_slots(lookahead_state, lookahead_epoch_start_slot)
lookahead_index = preferences.proposal_slot - lookahead_epoch_start_slot
if lookahead_state.proposer_lookahead[lookahead_index] != preferences.validator_index:
state = store.block_states[preferences.dependent_root].copy()
if state.slot < lookahead_start_slot:
process_slots(state, lookahead_start_slot)
lookahead_index = preferences.proposal_slot - lookahead_start_slot
if state.proposer_lookahead[lookahead_index] != preferences.validator_index:
raise GossipReject("validator is not the proposer for the given slot")

# [REJECT] The signature is valid
validator = lookahead_state.validators[preferences.validator_index]
domain = get_domain(lookahead_state, DOMAIN_PROPOSER_PREFERENCES, proposal_epoch)
validator = state.validators[preferences.validator_index]
domain = get_domain(state, DOMAIN_PROPOSER_PREFERENCES, proposal_epoch)
signing_root = compute_signing_root(preferences, domain)
if not bls.Verify(validator.pubkey, signing_root, signed_proposer_preferences.signature):
raise GossipReject("invalid proposer preferences signature")
Expand Down
11 changes: 6 additions & 5 deletions specs/heze/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,15 @@ def on_inclusion_list(store: Store, signed_inclusion_list: SignedInclusionList)
assert is_valid_dependent_root(store, inclusion_list.dependent_root, dependent_slot)

# Verify the validator is in the inclusion list committee
dependent_state = store.block_states[inclusion_list.dependent_root].copy()
if dependent_state.slot < inclusion_list.slot:
process_slots(dependent_state, inclusion_list.slot)
committee = get_inclusion_list_committee(dependent_state, inclusion_list.slot)
state = store.block_states[inclusion_list.dependent_root].copy()
lookahead_start_slot = compute_shuffling_lookahead_start_slot(epoch)
if state.slot < lookahead_start_slot:
process_slots(state, lookahead_start_slot)
committee = get_inclusion_list_committee(state, inclusion_list.slot)
assert inclusion_list.validator_index in committee

# Verify the signature
assert is_valid_inclusion_list_signature(dependent_state, signed_inclusion_list)
assert is_valid_inclusion_list_signature(state, signed_inclusion_list)

# The inclusion list is timely if it arrives in its slot before the deadline
seconds_since_genesis = store.time - store.genesis_time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,28 +443,28 @@ def setup_lookahead_boundary_preferences(spec, state):
lookahead lower bound for the proposal slot.
"""
lookahead_epoch = spec.Epoch(spec.MIN_SEED_LOOKAHEAD + 3)
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
store, blocks = setup_store_with_advanced_state(spec, state, lookahead_epoch_start_slot)
lookahead_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
store, blocks = setup_store_with_advanced_state(spec, state, lookahead_start_slot)

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

lookahead_state = dependent_state.copy()
spec.process_slots(lookahead_state, lookahead_epoch_start_slot)
spec.process_slots(lookahead_state, lookahead_start_slot)
proposal_slot = spec.compute_start_slot_at_epoch(
spec.Epoch(lookahead_epoch + spec.MIN_SEED_LOOKAHEAD)
)
lookahead_index = proposal_slot - lookahead_epoch_start_slot
lookahead_index = proposal_slot - lookahead_start_slot
signed_prefs = build_signed_proposer_preferences(
spec,
lookahead_state,
proposal_slot=proposal_slot,
validator_index=lookahead_state.proposer_lookahead[lookahead_index],
dependent_root=dependent_root,
)
return store, blocks, signed_prefs, lookahead_epoch_start_slot
return store, blocks, signed_prefs, lookahead_start_slot


@with_gloas_and_later
Expand All @@ -478,7 +478,7 @@ def test_gossip_proposer_preferences__ignore_outside_lookahead_disparity(spec, s
anchor_state = state.copy()
yield "topic", "meta", "proposer_preferences"

store, blocks, signed_prefs, lookahead_epoch_start_slot = setup_lookahead_boundary_preferences(
store, blocks, signed_prefs, lookahead_start_slot = setup_lookahead_boundary_preferences(
spec, state
)

Expand All @@ -489,7 +489,7 @@ def test_gossip_proposer_preferences__ignore_outside_lookahead_disparity(spec, s
yield get_filename(signed_prefs), signed_prefs

time_ms = (
spec.compute_time_at_slot_ms(store, lookahead_epoch_start_slot)
spec.compute_time_at_slot_ms(store, lookahead_start_slot)
- spec.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY
- 1
)
Expand Down Expand Up @@ -529,7 +529,7 @@ def test_gossip_proposer_preferences__valid_at_lookahead_disparity_edge(spec, st
anchor_state = state.copy()
yield "topic", "meta", "proposer_preferences"

store, blocks, signed_prefs, lookahead_epoch_start_slot = setup_lookahead_boundary_preferences(
store, blocks, signed_prefs, lookahead_start_slot = setup_lookahead_boundary_preferences(
spec, state
)

Expand All @@ -540,7 +540,7 @@ def test_gossip_proposer_preferences__valid_at_lookahead_disparity_edge(spec, st
yield get_filename(signed_prefs), signed_prefs

time_ms = (
spec.compute_time_at_slot_ms(store, lookahead_epoch_start_slot)
spec.compute_time_at_slot_ms(store, lookahead_start_slot)
- spec.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY
)
yield "current_time_ms", "meta", int(time_ms)
Expand Down Expand Up @@ -1020,16 +1020,13 @@ def test_gossip_proposer_preferences__reject_dependent_root_at_lookahead_epoch_s

proposal_slot, validator_index = find_upcoming_proposal_slot(spec, state)
proposal_epoch = spec.compute_epoch_at_slot(proposal_slot)
lookahead_epoch = spec.Epoch(proposal_epoch - spec.MIN_SEED_LOOKAHEAD)
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
lookahead_start_slot = spec.compute_shuffling_lookahead_start_slot(proposal_epoch)

boundary_block = next(
signed_block
for signed_block in blocks
if signed_block.message.slot == lookahead_epoch_start_slot
signed_block for signed_block in blocks if signed_block.message.slot == lookahead_start_slot
)
dependent_root = boundary_block.message.hash_tree_root()
assert store.block_states[dependent_root].slot == lookahead_epoch_start_slot
assert store.block_states[dependent_root].slot == lookahead_start_slot

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

proposal_slot, validator_index = find_upcoming_proposal_slot(spec, state)
proposal_epoch = spec.compute_epoch_at_slot(proposal_slot)
lookahead_epoch = spec.Epoch(proposal_epoch - spec.MIN_SEED_LOOKAHEAD)
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(lookahead_epoch)
lookahead_start_slot = spec.compute_shuffling_lookahead_start_slot(proposal_epoch)

# Fork off two slots before the lookahead epoch start and build a branch
# whose first block stays before the epoch start and whose second block
# crosses it.
fork_parent_root = spec.get_block_root_at_slot(state, spec.Slot(lookahead_epoch_start_slot - 2))
fork_parent_root = spec.get_block_root_at_slot(state, spec.Slot(lookahead_start_slot - 2))
fork_state = store.block_states[fork_parent_root].copy()
fork_blocks = []
for _ in range(2):
Expand All @@ -1168,8 +1164,8 @@ def test_gossip_proposer_preferences__valid_dependent_root_on_fork(spec, state):
store.block_states[block_root] = fork_state.copy()
fork_blocks.append(signed_fork_block)
dependent_root = fork_blocks[0].message.hash_tree_root()
assert store.blocks[dependent_root].slot == lookahead_epoch_start_slot - 1
assert fork_blocks[1].message.slot == lookahead_epoch_start_slot
assert store.blocks[dependent_root].slot == lookahead_start_slot - 1
assert fork_blocks[1].message.slot == lookahead_start_slot

yield "state", anchor_state
seen = get_seen(spec)
Expand Down Expand Up @@ -1222,7 +1218,7 @@ def test_gossip_proposer_preferences__valid_dependent_root_across_empty_epochs(s
yield "topic", "meta", "proposer_preferences"

current_epoch = spec.Epoch(spec.MIN_SEED_LOOKAHEAD + 2)
lookahead_epoch_start_slot = spec.compute_start_slot_at_epoch(current_epoch)
lookahead_start_slot = spec.compute_start_slot_at_epoch(current_epoch)

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

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

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