Merge pull request #1477 from ethereum/forkchoice-future-blocks
Forkchoice mods
This commit is contained in:
commit
1aad31df59
|
@ -238,6 +238,12 @@ def on_block(store: Store, block: BeaconBlock) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def on_attestation(store: Store, attestation: Attestation) -> None:
|
def on_attestation(store: Store, attestation: Attestation) -> None:
|
||||||
|
"""
|
||||||
|
Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
|
||||||
|
|
||||||
|
An ``attestation`` that is asserted as invalid may be valid at a later time,
|
||||||
|
consider scheduling it for later processing in such case.
|
||||||
|
"""
|
||||||
target = attestation.data.target
|
target = attestation.data.target
|
||||||
|
|
||||||
# Attestations must be from the current or previous epoch
|
# Attestations must be from the current or previous epoch
|
||||||
|
@ -248,10 +254,17 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
|
||||||
# Cannot calculate the current shuffling if have not seen the target
|
# Cannot calculate the current shuffling if have not seen the target
|
||||||
assert target.root in store.blocks
|
assert target.root in store.blocks
|
||||||
|
|
||||||
|
# Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
|
||||||
|
assert target.root in store.blocks
|
||||||
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
|
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
|
||||||
base_state = store.block_states[target.root].copy()
|
base_state = store.block_states[target.root].copy()
|
||||||
assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
|
assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
|
||||||
|
|
||||||
|
# Attestations must be for a known block. If block is unknown, delay consideration until the block is found
|
||||||
|
assert attestation.data.beacon_block_root in store.blocks
|
||||||
|
# Attestations must not be for blocks in the future. If not, the attestation should not be considered
|
||||||
|
assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot
|
||||||
|
|
||||||
# Store target checkpoint state if not yet seen
|
# Store target checkpoint state if not yet seen
|
||||||
if target not in store.checkpoint_states:
|
if target not in store.checkpoint_states:
|
||||||
process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
|
process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
from eth2spec.test.context import with_all_phases, spec_state_test
|
from eth2spec.test.context import with_all_phases, spec_state_test
|
||||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||||
from eth2spec.test.helpers.attestations import get_valid_attestation
|
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation
|
||||||
from eth2spec.test.helpers.state import state_transition_and_sign_block
|
from eth2spec.test.helpers.state import transition_to, state_transition_and_sign_block
|
||||||
|
|
||||||
|
|
||||||
def run_on_attestation(spec, state, store, attestation, valid=True):
|
def run_on_attestation(spec, state, store, attestation, valid=True):
|
||||||
|
@ -89,18 +88,48 @@ def test_on_attestation_past_epoch(spec, state):
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_on_attestation_target_not_in_store(spec, state):
|
def test_on_attestation_target_not_in_store(spec, state):
|
||||||
store = spec.get_genesis_store(state)
|
store = spec.get_genesis_store(state)
|
||||||
time = 100
|
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
||||||
spec.on_tick(store, time)
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
# move to next epoch to make block new target
|
# move to immediately before next epoch to make block new target
|
||||||
state.slot += spec.SLOTS_PER_EPOCH
|
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
|
||||||
|
|
||||||
block = build_empty_block_for_next_slot(spec, state)
|
target_block = build_empty_block_for_next_slot(spec, state)
|
||||||
state_transition_and_sign_block(spec, state, block)
|
state_transition_and_sign_block(spec, state, target_block)
|
||||||
|
|
||||||
# do not add block to store
|
# do not add target block to store
|
||||||
|
|
||||||
|
attestation = get_valid_attestation(spec, state, slot=target_block.slot)
|
||||||
|
assert attestation.data.target.root == target_block.signing_root()
|
||||||
|
|
||||||
|
run_on_attestation(spec, state, store, attestation, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases
|
||||||
|
@spec_state_test
|
||||||
|
def test_on_attestation_beacon_block_not_in_store(spec, state):
|
||||||
|
store = spec.get_genesis_store(state)
|
||||||
|
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
||||||
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
|
# move to immediately before next epoch to make block new target
|
||||||
|
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
|
||||||
|
|
||||||
|
target_block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
state_transition_and_sign_block(spec, state, target_block)
|
||||||
|
|
||||||
|
# store target in store
|
||||||
|
spec.on_block(store, target_block)
|
||||||
|
|
||||||
|
head_block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
state_transition_and_sign_block(spec, state, head_block)
|
||||||
|
|
||||||
|
# do not add head block to store
|
||||||
|
|
||||||
|
attestation = get_valid_attestation(spec, state, slot=head_block.slot)
|
||||||
|
assert attestation.data.target.root == target_block.signing_root()
|
||||||
|
assert attestation.data.beacon_block_root == head_block.signing_root()
|
||||||
|
|
||||||
attestation = get_valid_attestation(spec, state, slot=block.slot)
|
|
||||||
run_on_attestation(spec, state, store, attestation, False)
|
run_on_attestation(spec, state, store, attestation, False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,6 +153,26 @@ def test_on_attestation_future_epoch(spec, state):
|
||||||
run_on_attestation(spec, state, store, attestation, False)
|
run_on_attestation(spec, state, store, attestation, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases
|
||||||
|
@spec_state_test
|
||||||
|
def test_on_attestation_future_block(spec, state):
|
||||||
|
store = spec.get_genesis_store(state)
|
||||||
|
time = spec.SECONDS_PER_SLOT * 5
|
||||||
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
|
block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
state_transition_and_sign_block(spec, state, block)
|
||||||
|
|
||||||
|
spec.on_block(store, block)
|
||||||
|
|
||||||
|
# attestation for slot immediately prior to the block being attested to
|
||||||
|
attestation = get_valid_attestation(spec, state, slot=block.slot - 1, signed=False)
|
||||||
|
attestation.data.beacon_block_root = block.signing_root()
|
||||||
|
sign_attestation(spec, state, attestation)
|
||||||
|
|
||||||
|
run_on_attestation(spec, state, store, attestation, False)
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_on_attestation_same_slot(spec, state):
|
def test_on_attestation_same_slot(spec, state):
|
||||||
|
|
|
@ -14,6 +14,16 @@ def next_slot(spec, state):
|
||||||
spec.process_slots(state, state.slot + 1)
|
spec.process_slots(state, state.slot + 1)
|
||||||
|
|
||||||
|
|
||||||
|
def transition_to(spec, state, slot):
|
||||||
|
"""
|
||||||
|
Transition to ``slot``.
|
||||||
|
"""
|
||||||
|
assert state.slot <= slot
|
||||||
|
for _ in range(slot - state.slot):
|
||||||
|
next_slot(spec, state)
|
||||||
|
assert state.slot == slot
|
||||||
|
|
||||||
|
|
||||||
def next_epoch(spec, state):
|
def next_epoch(spec, state):
|
||||||
"""
|
"""
|
||||||
Transition to the start slot of the next epoch
|
Transition to the start slot of the next epoch
|
||||||
|
|
Loading…
Reference in New Issue