Skip to content

Commit

Permalink
Merge pull request #1818 from ethereum/v011x
Browse files Browse the repository at this point in the history
v0.11 multiple blocks in single slot patch
  • Loading branch information
djrtwo authored May 18, 2020
2 parents 524b84d + 74c900f commit feb910e
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 64 deletions.
4 changes: 3 additions & 1 deletion specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock)

```python
def process_slots(state: BeaconState, slot: Slot) -> None:
assert state.slot <= slot
assert state.slot < slot
while state.slot < slot:
process_slot(state)
# Process epoch on the start slot of the next epoch
Expand Down Expand Up @@ -1494,6 +1494,8 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
# Verify that the slots match
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
assert block.proposer_index == get_beacon_proposer_index(state)
# Verify that the parent matches
Expand Down
3 changes: 2 additions & 1 deletion tests/core/pyspec/eth2spec/test/helpers/attestations.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ def fill_aggregate_attestation(spec, state, attestation, signed=False):


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:
spec.process_attestation(state, attestation)

Expand Down
15 changes: 10 additions & 5 deletions tests/core/pyspec/eth2spec/test/helpers/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
# use stub state to get proposer index of future slot
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)
return proposer_index

Expand Down Expand Up @@ -52,15 +53,19 @@ def sign_block(spec, state, block, proposer_index=None):


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)


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).
"""
block = build_empty_block(spec, state)
block = build_empty_block(spec, state, slot)
transition_unsigned_block(spec, state, block)


Expand All @@ -73,7 +78,7 @@ def build_empty_block(spec, state, slot=None):
slot = state.slot
if slot < state.slot:
raise Exception("build_empty_block cannot build blocks for past slots")
if slot > state.slot:
if state.slot < slot:
# transition forward in copied state to grab relevant data from state
state = state.copy()
spec.process_slots(state, slot)
Expand Down
24 changes: 21 additions & 3 deletions tests/core/pyspec/eth2spec/test/helpers/state.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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):
Expand All @@ -17,7 +17,8 @@ def next_slots(spec, state, slots):
"""
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):
Expand All @@ -30,12 +31,29 @@ def transition_to(spec, state, 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 next_epoch(spec, state):
"""
Transition to the start slot of the next 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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
from eth2spec.test.helpers.state import (
next_slot,
next_slots,
next_epoch,
transition_to,
next_epoch_via_block,
transition_to_slot_via_block,
)
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.utils.ssz.ssz_typing import Bitlist


Expand Down Expand Up @@ -47,9 +46,7 @@ def test_success_multi_proposer_index_iterations(spec, state):
@spec_state_test
def test_success_previous_epoch(spec, state):
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
transition_to(spec, state, spec.SLOTS_PER_EPOCH - 1)
next_epoch(spec, state)
apply_empty_block(spec, state)
next_epoch_via_block(spec, state)

yield from run_attestation_processing(spec, state, attestation)

Expand Down Expand Up @@ -79,8 +76,7 @@ def test_after_epoch_slots(spec, state):
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)

# increment past latest inclusion slot
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1)
apply_empty_block(spec, state)
transition_to_slot_via_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1)

yield from run_attestation_processing(spec, state, attestation, False)

Expand Down Expand Up @@ -151,8 +147,8 @@ def test_invalid_index(spec, state):
@with_all_phases
@spec_state_test
def test_mismatched_target_and_slot(spec, state):
next_epoch(spec, state)
next_epoch(spec, state)
next_epoch_via_block(spec, state)
next_epoch_via_block(spec, state)

attestation = get_valid_attestation(spec, state, on_time=False)
attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
from eth2spec.test.helpers.attestations import sign_indexed_attestation
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \
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 (
get_balance,
next_epoch,
next_epoch_via_block,
)


Expand Down Expand Up @@ -91,8 +90,7 @@ def test_success_double(spec, state):
@with_all_phases
@spec_state_test
def test_success_surround(spec, state):
next_epoch(spec, state)
apply_empty_block(spec, state)
next_epoch_via_block(spec, state)

state.current_justified_checkpoint.epoch += 1
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ def prepare_state_for_header_processing(spec, state):
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:
- pre-state ('pre')
- block ('block')
- post-state ('post').
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 'block', block
Expand Down Expand Up @@ -68,6 +69,22 @@ def test_invalid_parent_root(spec, state):
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
@spec_state_test
def test_proposer_slashed(spec, state):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

# 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.
spec.process_slot(state)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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, get_balance
from eth2spec.test.helpers.state import next_epoch_via_block, get_balance
from eth2spec.test.context import (
PHASE0,
with_all_phases_except,
Expand Down Expand Up @@ -64,8 +63,7 @@ def test_reveal_from_current_epoch(spec, state):
@spec_state_test
@never_bls
def test_reveal_from_past_epoch(spec, state):
next_epoch(spec, state)
apply_empty_block(spec, state)
next_epoch_via_block(spec, state)
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)
Expand Down
Loading

0 comments on commit feb910e

Please sign in to comment.