Merge pull request #1823 from ethereum/v0113-dev-merge

backport v0.11.3 to dev
This commit is contained in:
Danny Ryan 2020-05-18 13:30:16 -06:00 committed by GitHub
commit 69fdcf664e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 177 additions and 63 deletions

View File

@ -1225,7 +1225,7 @@ def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock)
```python ```python
def process_slots(state: BeaconState, slot: Slot) -> None: def process_slots(state: BeaconState, slot: Slot) -> None:
assert state.slot <= slot assert state.slot < slot
while state.slot < slot: while state.slot < slot:
process_slot(state) process_slot(state)
# Process epoch on the start slot of the next epoch # Process epoch on the start slot of the next epoch
@ -1584,6 +1584,8 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
def process_block_header(state: BeaconState, block: BeaconBlock) -> None: def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
# Verify that the slots match # Verify that the slots match
assert block.slot == state.slot assert block.slot == state.slot
# Verify that the block is newer than latest block header
assert block.slot > state.latest_block_header.slot
# Verify that proposer index is the correct index # Verify that proposer index is the correct index
assert block.proposer_index == get_beacon_proposer_index(state) assert block.proposer_index == get_beacon_proposer_index(state)
# Verify that the parent matches # Verify that the parent matches

View File

@ -283,7 +283,8 @@ def fill_aggregate_attestation(spec, state, attestation, signed=False):
def add_attestations_to_state(spec, state, attestations, slot): def add_attestations_to_state(spec, state, attestations, slot):
spec.process_slots(state, slot) if state.slot < slot:
spec.process_slots(state, slot)
for attestation in attestations: for attestation in attestations:
spec.process_attestation(state, attestation) spec.process_attestation(state, attestation)

View File

@ -15,7 +15,8 @@ def get_proposer_index_maybe(spec, state, slot, proposer_index=None):
" Signing block is slow due to transition for proposer index calculation.") " Signing block is slow due to transition for proposer index calculation.")
# use stub state to get proposer index of future slot # use stub state to get proposer index of future slot
stub_state = state.copy() stub_state = state.copy()
spec.process_slots(stub_state, slot) if stub_state.slot < slot:
spec.process_slots(stub_state, slot)
proposer_index = spec.get_beacon_proposer_index(stub_state) proposer_index = spec.get_beacon_proposer_index(stub_state)
return proposer_index return proposer_index
@ -52,15 +53,19 @@ def sign_block(spec, state, block, proposer_index=None):
def transition_unsigned_block(spec, state, block): def transition_unsigned_block(spec, state, block):
spec.process_slots(state, block.slot) assert state.slot < block.slot # Preserve assertion from state transition to avoid strange pre-states from testing
if state.slot < block.slot:
spec.process_slots(state, block.slot)
assert state.latest_block_header.slot < block.slot # There may not already be a block in this slot or past it.
assert state.slot == block.slot # The block must be for this slot
spec.process_block(state, block) spec.process_block(state, block)
def apply_empty_block(spec, state): def apply_empty_block(spec, state, slot=None):
""" """
Transition via an empty block (on current slot, assuming no block has been applied yet). Transition via an empty block (on current slot, assuming no block has been applied yet).
""" """
block = build_empty_block(spec, state) block = build_empty_block(spec, state, slot)
transition_unsigned_block(spec, state, block) transition_unsigned_block(spec, state, block)
@ -71,6 +76,12 @@ def build_empty_block(spec, state, slot=None):
""" """
if slot is None: if slot is None:
slot = state.slot slot = state.slot
if slot < state.slot:
raise Exception("build_empty_block cannot build blocks for past slots")
if state.slot < slot:
# transition forward in copied state to grab relevant data from state
state = state.copy()
spec.process_slots(state, slot)
state, parent_block_root = get_state_and_beacon_parent_root_at_slot(spec, state, slot) state, parent_block_root = get_state_and_beacon_parent_root_at_slot(spec, state, slot)
empty_block = spec.BeaconBlock() empty_block = spec.BeaconBlock()

View File

@ -1,5 +1,5 @@
from eth2spec.test.context import expect_assertion_error from eth2spec.test.context import expect_assertion_error
from eth2spec.test.helpers.block import sign_block, transition_unsigned_block from eth2spec.test.helpers.block import apply_empty_block, sign_block, transition_unsigned_block
def get_balance(state, index): def get_balance(state, index):
@ -17,7 +17,8 @@ def next_slots(spec, state, slots):
""" """
Transition given slots forward. Transition given slots forward.
""" """
spec.process_slots(state, state.slot + slots) if slots > 0:
spec.process_slots(state, state.slot + slots)
def transition_to(spec, state, slot): def transition_to(spec, state, slot):
@ -30,6 +31,15 @@ def transition_to(spec, state, slot):
assert state.slot == slot assert state.slot == slot
def transition_to_slot_via_block(spec, state, slot):
"""
Transition to ``slot`` via an empty block transition
"""
assert state.slot < slot
apply_empty_block(spec, state, slot)
assert state.slot == slot
def transition_to_valid_shard_slot(spec, state): def transition_to_valid_shard_slot(spec, state):
""" """
Transition to slot `spec.PHASE_1_GENESIS_SLOT + 1` and fork at `spec.PHASE_1_GENESIS_SLOT`. Transition to slot `spec.PHASE_1_GENESIS_SLOT + 1` and fork at `spec.PHASE_1_GENESIS_SLOT`.
@ -45,7 +55,15 @@ def next_epoch(spec, state):
Transition to the start slot of the next epoch Transition to the start slot of the next epoch
""" """
slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
spec.process_slots(state, slot) if slot > state.slot:
spec.process_slots(state, slot)
def next_epoch_via_block(spec, state):
"""
Transition to the start slot of the next epoch via a full block transition
"""
apply_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH)
def get_state_root(spec, state, slot) -> bytes: def get_state_root(spec, state, slot) -> bytes:

View File

@ -15,10 +15,9 @@ from eth2spec.test.helpers.attestations import (
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
next_slot, next_slot,
next_slots, next_slots,
next_epoch, next_epoch_via_block,
transition_to, transition_to_slot_via_block,
) )
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.utils.ssz.ssz_typing import Bitlist from eth2spec.utils.ssz.ssz_typing import Bitlist
@ -47,9 +46,7 @@ def test_success_multi_proposer_index_iterations(spec, state):
@spec_state_test @spec_state_test
def test_success_previous_epoch(spec, state): def test_success_previous_epoch(spec, state):
attestation = get_valid_attestation(spec, state, signed=True, on_time=False) attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
transition_to(spec, state, spec.SLOTS_PER_EPOCH - 1) next_epoch_via_block(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation) yield from run_attestation_processing(spec, state, attestation)
@ -79,8 +76,7 @@ def test_after_epoch_slots(spec, state):
attestation = get_valid_attestation(spec, state, signed=True, on_time=False) attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
# increment past latest inclusion slot # increment past latest inclusion slot
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1) transition_to_slot_via_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation, False) yield from run_attestation_processing(spec, state, attestation, False)
@ -151,8 +147,8 @@ def test_invalid_index(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_mismatched_target_and_slot(spec, state): def test_mismatched_target_and_slot(spec, state):
next_epoch(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state) next_epoch_via_block(spec, state)
attestation = get_valid_attestation(spec, state, on_time=False) attestation = get_valid_attestation(spec, state, on_time=False)
attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH

View File

@ -5,10 +5,9 @@ from eth2spec.test.context import (
from eth2spec.test.helpers.attestations import sign_indexed_attestation from eth2spec.test.helpers.attestations import sign_indexed_attestation
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \ from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \
get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
get_balance, get_balance,
next_epoch, next_epoch_via_block,
) )
@ -91,8 +90,7 @@ def test_success_double(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_success_surround(spec, state): def test_success_surround(spec, state):
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state)
state.current_justified_checkpoint.epoch += 1 state.current_justified_checkpoint.epoch += 1
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)

View File

@ -9,7 +9,7 @@ def prepare_state_for_header_processing(spec, state):
spec.process_slots(state, state.slot + 1) spec.process_slots(state, state.slot + 1)
def run_block_header_processing(spec, state, block, valid=True): def run_block_header_processing(spec, state, block, prepare_state=True, valid=True):
""" """
Run ``process_block_header``, yielding: Run ``process_block_header``, yielding:
- pre-state ('pre') - pre-state ('pre')
@ -17,7 +17,8 @@ def run_block_header_processing(spec, state, block, valid=True):
- post-state ('post'). - post-state ('post').
If ``valid == False``, run expecting ``AssertionError`` If ``valid == False``, run expecting ``AssertionError``
""" """
prepare_state_for_header_processing(spec, state) if prepare_state:
prepare_state_for_header_processing(spec, state)
yield 'pre', state yield 'pre', state
yield 'block', block yield 'block', block
@ -68,6 +69,22 @@ def test_invalid_parent_root(spec, state):
yield from run_block_header_processing(spec, state, block, valid=False) yield from run_block_header_processing(spec, state, block, valid=False)
@with_all_phases
@spec_state_test
def test_invalid_multiple_blocks_single_slot(spec, state):
block = build_empty_block_for_next_slot(spec, state)
prepare_state_for_header_processing(spec, state)
spec.process_block_header(state, block)
assert state.latest_block_header.slot == state.slot
child_block = block.copy()
child_block.parent_root = block.hash_tree_root()
yield from run_block_header_processing(spec, state, child_block, prepare_state=False, valid=False)
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_proposer_slashed(spec, state): def test_proposer_slashed(spec, state):

View File

@ -18,7 +18,8 @@ def run_epoch_processing_to(spec, state, process_name: str):
slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH)
# transition state to slot before epoch state transition # transition state to slot before epoch state transition
spec.process_slots(state, slot - 1) if state.slot < slot - 1:
spec.process_slots(state, slot - 1)
# start transitioning, do one slot update before the epoch itself. # start transitioning, do one slot update before the epoch itself.
spec.process_slot(state) spec.process_slot(state)

View File

@ -1,8 +1,14 @@
from eth2spec.utils import bls from eth2spec.utils import bls
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot, next_epoch from eth2spec.test.helpers.state import (
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block, \ get_balance, state_transition_and_sign_block,
transition_unsigned_block next_slot, next_epoch, next_epoch_via_block,
)
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot, build_empty_block,
sign_block,
transition_unsigned_block,
)
from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, get_indexed_attestation_participants from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, get_indexed_attestation_participants
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect
@ -46,10 +52,12 @@ def test_same_slot_block_transition(spec, state):
yield 'pre', state yield 'pre', state
signed_block = state_transition_and_sign_block(spec, state, block) assert state.slot == block.slot
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
yield 'blocks', [signed_block] yield 'blocks', [signed_block]
yield 'post', state yield 'post', None
@with_all_phases @with_all_phases
@ -72,6 +80,81 @@ def test_empty_block_transition(spec, state):
assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.Bytes32() assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.Bytes32()
def process_and_sign_block_without_header_validations(spec, state, block):
"""
Artificially bypass the restrictions in the state transition to transition and sign block
WARNING UNSAFE: Only use when generating valid-looking invalid blocks for test vectors
"""
# Perform single mutation in `process_block_header`
state.latest_block_header = spec.BeaconBlockHeader(
slot=block.slot,
proposer_index=block.proposer_index,
parent_root=block.parent_root,
state_root=spec.Bytes32(),
body_root=block.body.hash_tree_root(),
)
# Perform rest of process_block transitions
spec.process_randao(state, block.body)
spec.process_eth1_data(state, block.body)
spec.process_operations(state, block.body)
# Insert post-state rot
block.state_root = state.hash_tree_root()
# Sign block
return sign_block(spec, state, block)
@with_phases(['phase0'])
@spec_state_test
def test_proposal_for_genesis_slot(spec, state):
assert state.slot == spec.GENESIS_SLOT
yield 'pre', state
block = build_empty_block(spec, state, spec.GENESIS_SLOT)
block.parent_root = state.latest_block_header.hash_tree_root()
# Show that normal path through transition fails
failed_state = state.copy()
expect_assertion_error(
lambda: spec.state_transition(failed_state, spec.SignedBeaconBlock(message=block), validate_result=False)
)
# Artificially bypass the restriction in the state transition to transition and sign block for test vectors
signed_block = process_and_sign_block_without_header_validations(spec, state, block)
yield 'blocks', [signed_block]
yield 'post', None
@with_all_phases
@spec_state_test
def test_parent_from_same_slot(spec, state):
yield 'pre', state
parent_block = build_empty_block_for_next_slot(spec, state)
signed_parent_block = state_transition_and_sign_block(spec, state, parent_block)
child_block = parent_block.copy()
child_block.parent_root = state.latest_block_header.hash_tree_root()
# Show that normal path through transition fails
failed_state = state.copy()
expect_assertion_error(
lambda: spec.state_transition(failed_state, spec.SignedBeaconBlock(message=child_block), validate_result=False)
)
# Artificially bypass the restriction in the state transition to transition and sign block for test vectors
signed_child_block = process_and_sign_block_without_header_validations(spec, state, child_block)
yield 'blocks', [signed_parent_block, signed_child_block]
yield 'post', None
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_invalid_state_root(spec, state): def test_invalid_state_root(spec, state):
@ -378,22 +461,19 @@ def test_proposer_after_inactive_index(spec, state):
state.validators[inactive_index].exit_epoch = spec.get_current_epoch(state) state.validators[inactive_index].exit_epoch = spec.get_current_epoch(state)
# skip forward, get brand new proposers # skip forward, get brand new proposers
next_epoch(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state) next_epoch_via_block(spec, state)
block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
while True: while True:
next_slot(spec, state)
proposer_index = spec.get_beacon_proposer_index(state) proposer_index = spec.get_beacon_proposer_index(state)
if proposer_index > inactive_index: if proposer_index > inactive_index:
# found a proposer that has a higher index than a disabled validator # found a proposer that has a higher index than a disabled validator
yield 'pre', state yield 'pre', state
# test if the proposer can be recognized correctly after the inactive validator # test if the proposer can be recognized correctly after the inactive validator
signed_block = state_transition_and_sign_block(spec, state, build_empty_block(spec, state)) signed_block = state_transition_and_sign_block(spec, state, build_empty_block_for_next_slot(spec, state))
yield 'blocks', [signed_block] yield 'blocks', [signed_block]
yield 'post', state yield 'post', state
break break
next_slot(spec, state)
@with_all_phases @with_all_phases
@ -411,16 +491,16 @@ def test_high_proposer_index(spec, state):
active_count = len(spec.get_active_validator_indices(state, current_epoch)) active_count = len(spec.get_active_validator_indices(state, current_epoch))
while True: while True:
next_slot(spec, state)
proposer_index = spec.get_beacon_proposer_index(state) proposer_index = spec.get_beacon_proposer_index(state)
if proposer_index >= active_count: if proposer_index >= active_count:
# found a proposer that has a higher index than the active validator count # found a proposer that has a higher index than the active validator count
yield 'pre', state yield 'pre', state
# test if the proposer can be recognized correctly, even while it has a high index. # test if the proposer can be recognized correctly, even while it has a high index.
signed_block = state_transition_and_sign_block(spec, state, build_empty_block(spec, state)) signed_block = state_transition_and_sign_block(spec, state, build_empty_block_for_next_slot(spec, state))
yield 'blocks', [signed_block] yield 'blocks', [signed_block]
yield 'post', state yield 'post', state
break break
next_slot(spec, state)
@with_all_phases @with_all_phases

View File

@ -51,7 +51,8 @@ def test_double_empty_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_over_epoch_boundary(spec, state): def test_over_epoch_boundary(spec, state):
spec.process_slots(state, state.slot + (spec.SLOTS_PER_EPOCH // 2)) if spec.SLOTS_PER_EPOCH > 1:
spec.process_slots(state, state.slot + (spec.SLOTS_PER_EPOCH // 2))
yield 'pre', state yield 'pre', state
slots = spec.SLOTS_PER_EPOCH slots = spec.SLOTS_PER_EPOCH
yield 'slots', slots yield 'slots', slots

View File

@ -1,6 +1,5 @@
from eth2spec.test.helpers.custody import get_valid_early_derived_secret_reveal from eth2spec.test.helpers.custody import get_valid_early_derived_secret_reveal
from eth2spec.test.helpers.block import apply_empty_block from eth2spec.test.helpers.state import next_epoch_via_block, get_balance
from eth2spec.test.helpers.state import next_epoch, get_balance
from eth2spec.test.context import ( from eth2spec.test.context import (
PHASE0, PHASE0,
with_all_phases_except, with_all_phases_except,
@ -64,8 +63,7 @@ def test_reveal_from_current_epoch(spec, state):
@spec_state_test @spec_state_test
@never_bls @never_bls
def test_reveal_from_past_epoch(spec, state): def test_reveal_from_past_epoch(spec, state):
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state)
randao_key_reveal = get_valid_early_derived_secret_reveal(spec, state, spec.get_current_epoch(state) - 1) randao_key_reveal = get_valid_early_derived_secret_reveal(spec, state, spec.get_current_epoch(state) - 1)
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False) yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)

View File

@ -1,7 +1,6 @@
from eth2spec.test.context import spec_state_test, never_bls, with_all_phases, with_phases from eth2spec.test.context import spec_state_test, never_bls, with_all_phases, with_phases
from eth2spec.test.helpers.state import next_epoch from eth2spec.test.helpers.state import next_epoch_via_block
from eth2spec.test.helpers.attestations import next_epoch_with_attestations from eth2spec.test.helpers.attestations import next_epoch_with_attestations
from eth2spec.test.helpers.block import apply_empty_block
def check_finality(spec, def check_finality(spec,
@ -58,10 +57,8 @@ def test_finality_no_updates_at_genesis(spec, state):
@never_bls @never_bls
def test_finality_rule_4(spec, state): def test_finality_rule_4(spec, state):
# get past first two epochs that finality does not run on # get past first two epochs that finality does not run on
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
yield 'pre', state yield 'pre', state
@ -86,10 +83,8 @@ def test_finality_rule_4(spec, state):
@never_bls @never_bls
def test_finality_rule_1(spec, state): def test_finality_rule_1(spec, state):
# get past first two epochs that finality does not run on # get past first two epochs that finality does not run on
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
yield 'pre', state yield 'pre', state
@ -116,10 +111,8 @@ def test_finality_rule_1(spec, state):
@never_bls @never_bls
def test_finality_rule_2(spec, state): def test_finality_rule_2(spec, state):
# get past first two epochs that finality does not run on # get past first two epochs that finality does not run on
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
yield 'pre', state yield 'pre', state
@ -152,10 +145,8 @@ def test_finality_rule_3(spec, state):
https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892 https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892
""" """
# get past first two epochs that finality does not run on # get past first two epochs that finality does not run on
next_epoch(spec, state) next_epoch_via_block(spec, state)
apply_empty_block(spec, state) next_epoch_via_block(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
yield 'pre', state yield 'pre', state