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
|
||||
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
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
|
||||
# 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
|
||||
if target not in store.checkpoint_states:
|
||||
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.helpers.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.helpers.attestations import get_valid_attestation
|
||||
from eth2spec.test.helpers.state import state_transition_and_sign_block
|
||||
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation
|
||||
from eth2spec.test.helpers.state import transition_to, state_transition_and_sign_block
|
||||
|
||||
|
||||
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
|
||||
def test_on_attestation_target_not_in_store(spec, state):
|
||||
store = spec.get_genesis_store(state)
|
||||
time = 100
|
||||
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
||||
spec.on_tick(store, time)
|
||||
|
||||
# move to next epoch to make block new target
|
||||
state.slot += spec.SLOTS_PER_EPOCH
|
||||
# move to immediately before next epoch to make block new target
|
||||
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
state_transition_and_sign_block(spec, state, block)
|
||||
target_block = build_empty_block_for_next_slot(spec, state)
|
||||
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)
|
||||
|
||||
|
||||
|
@ -124,6 +153,26 @@ def test_on_attestation_future_epoch(spec, state):
|
|||
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
|
||||
@spec_state_test
|
||||
def test_on_attestation_same_slot(spec, state):
|
||||
|
|
|
@ -14,6 +14,16 @@ def next_slot(spec, state):
|
|||
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):
|
||||
"""
|
||||
Transition to the start slot of the next epoch
|
||||
|
|
Loading…
Reference in New Issue