Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.11 multiple blocks in single slot patch #1818

Merged
merged 4 commits into from
May 18, 2020
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
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