mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-03-01 18:50:35 +00:00
Add get_proposer_head
and should_override_forkchoice_update
tests
This commit is contained in:
parent
0f61819e5c
commit
24b4d46903
@ -0,0 +1,162 @@
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_bellatrix_and_later,
|
||||
with_presets,
|
||||
)
|
||||
from eth2spec.test.helpers.constants import (
|
||||
MINIMAL,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
get_valid_attestation_at_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
apply_next_epoch_with_attestations,
|
||||
apply_next_slots_with_attestations,
|
||||
get_genesis_forkchoice_store_and_block,
|
||||
on_tick_and_append_step,
|
||||
tick_and_add_block,
|
||||
tick_and_run_on_attestation,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
state_transition_and_sign_block,
|
||||
next_epoch,
|
||||
next_slot,
|
||||
)
|
||||
|
||||
|
||||
@with_bellatrix_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL], reason="too slow")
|
||||
def test_should_override_forkchoice_update__false(spec, state):
|
||||
test_steps = []
|
||||
# Initialization
|
||||
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||
yield 'anchor_state', state
|
||||
yield 'anchor_block', anchor_block
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
assert spec.get_head(store) == signed_block.message.hash_tree_root()
|
||||
|
||||
# Proposer of next slot
|
||||
head_root = spec.get_head(store)
|
||||
|
||||
# Next slot
|
||||
next_slot(spec, state)
|
||||
slot = state.slot
|
||||
|
||||
current_time = slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
|
||||
assert not spec.should_override_forkchoice_update(store, head_root)
|
||||
|
||||
yield 'steps', test_steps
|
||||
|
||||
|
||||
@with_bellatrix_and_later
|
||||
@spec_state_test
|
||||
def test_should_override_forkchoice_update__true(spec, state):
|
||||
test_steps = []
|
||||
# Initialization
|
||||
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||
yield 'anchor_state', state
|
||||
yield 'anchor_block', anchor_block
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
next_epoch(spec, state)
|
||||
on_tick_and_append_step(spec, store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT, test_steps)
|
||||
|
||||
# Fill epoch 1 to 3
|
||||
for _ in range(3):
|
||||
state, store, _ = yield from apply_next_epoch_with_attestations(
|
||||
spec, state, store, True, True, test_steps=test_steps)
|
||||
|
||||
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == 4
|
||||
assert state.current_justified_checkpoint.epoch == store.justified_checkpoint.epoch == 3
|
||||
assert state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 2
|
||||
|
||||
# Make an empty block
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
|
||||
# Fill a slot (parent)
|
||||
state, store, signed_parent_block = yield from apply_next_slots_with_attestations(
|
||||
spec, state, store, 1, True, True, test_steps)
|
||||
|
||||
# Fill a slot with attestations to its parent
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
parent_block_slot = block.slot - 1
|
||||
block.body.attestations = get_valid_attestation_at_slot(
|
||||
state,
|
||||
spec,
|
||||
parent_block_slot,
|
||||
)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
# Make the head block late
|
||||
attesting_cutoff = spec.config.SECONDS_PER_SLOT // spec.INTERVALS_PER_SLOT
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time + attesting_cutoff
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
assert spec.get_current_slot(store) == block.slot
|
||||
|
||||
# Check conditions
|
||||
head_root = spec.get_head(store)
|
||||
head_block = store.blocks[head_root]
|
||||
parent_root = head_block.parent_root
|
||||
assert parent_root == signed_parent_block.message.hash_tree_root()
|
||||
parent_block = store.blocks[parent_root]
|
||||
|
||||
# Add attestations to the parent block
|
||||
temp_state = state.copy()
|
||||
next_slot(spec, temp_state)
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time + 1
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
attestations = get_valid_attestation_at_slot(
|
||||
temp_state,
|
||||
spec,
|
||||
slot_to_attest=temp_state.slot - 1,
|
||||
beacon_block_root=parent_root,
|
||||
)
|
||||
current_slot = spec.get_current_slot(store)
|
||||
for attestation in attestations:
|
||||
yield from tick_and_run_on_attestation(spec, store, attestation, test_steps)
|
||||
|
||||
current_slot = spec.get_current_slot(store)
|
||||
proposal_slot = head_block.slot + 1
|
||||
|
||||
# The conditions in `get_proposer_head`
|
||||
assert spec.is_head_late(store, head_root)
|
||||
assert spec.is_shuffling_stable(proposal_slot)
|
||||
assert spec.is_ffg_competitive(store, head_root, parent_root)
|
||||
assert spec.is_finalization_ok(store, proposal_slot)
|
||||
|
||||
# TODO: proposing_reorg_slot
|
||||
|
||||
# Single slot re-org.
|
||||
parent_slot_ok = parent_block.slot + 1 == head_block.slot
|
||||
proposing_on_time = spec.is_proposing_on_time(store)
|
||||
assert proposing_on_time
|
||||
assert parent_slot_ok and proposal_slot == current_slot and proposing_on_time
|
||||
|
||||
assert spec.is_head_weak(store, head_root)
|
||||
assert spec.is_parent_strong(store, parent_root)
|
||||
|
||||
assert spec.should_override_forkchoice_update(store, head_root)
|
||||
|
||||
# TODO: export the `should_override_forkchoice_update` result to test vectors?
|
||||
|
||||
yield 'steps', test_steps
|
@ -51,19 +51,21 @@ def run_attestation_processing(spec, state, attestation, valid=True):
|
||||
yield 'post', state
|
||||
|
||||
|
||||
def build_attestation_data(spec, state, slot, index, shard=None):
|
||||
def build_attestation_data(spec, state, slot, index, beacon_block_root=None, shard=None):
|
||||
assert state.slot >= slot
|
||||
|
||||
if slot == state.slot:
|
||||
block_root = build_empty_block_for_next_slot(spec, state).parent_root
|
||||
if beacon_block_root is not None:
|
||||
pass
|
||||
elif slot == state.slot:
|
||||
beacon_block_root = build_empty_block_for_next_slot(spec, state).parent_root
|
||||
else:
|
||||
block_root = spec.get_block_root_at_slot(state, slot)
|
||||
beacon_block_root = spec.get_block_root_at_slot(state, slot)
|
||||
|
||||
current_epoch_start_slot = spec.compute_start_slot_at_epoch(spec.get_current_epoch(state))
|
||||
if slot < current_epoch_start_slot:
|
||||
epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state))
|
||||
elif slot == current_epoch_start_slot:
|
||||
epoch_boundary_root = block_root
|
||||
epoch_boundary_root = beacon_block_root
|
||||
else:
|
||||
epoch_boundary_root = spec.get_block_root(state, spec.get_current_epoch(state))
|
||||
|
||||
@ -77,7 +79,7 @@ def build_attestation_data(spec, state, slot, index, shard=None):
|
||||
data = spec.AttestationData(
|
||||
slot=slot,
|
||||
index=index,
|
||||
beacon_block_root=block_root,
|
||||
beacon_block_root=beacon_block_root,
|
||||
source=spec.Checkpoint(epoch=source_epoch, root=source_root),
|
||||
target=spec.Checkpoint(epoch=spec.compute_epoch_at_slot(slot), root=epoch_boundary_root),
|
||||
)
|
||||
@ -91,6 +93,7 @@ def get_valid_attestation(spec,
|
||||
slot=None,
|
||||
index=None,
|
||||
filter_participant_set=None,
|
||||
beacon_block_root=None,
|
||||
signed=False):
|
||||
# If filter_participant_set filters everything, the attestation has 0 participants, and cannot be signed.
|
||||
# Thus strictly speaking invalid when no participant is added later.
|
||||
@ -99,9 +102,7 @@ def get_valid_attestation(spec,
|
||||
if index is None:
|
||||
index = 0
|
||||
|
||||
attestation_data = build_attestation_data(
|
||||
spec, state, slot=slot, index=index
|
||||
)
|
||||
attestation_data = build_attestation_data(spec, state, slot=slot, index=index, beacon_block_root=beacon_block_root)
|
||||
|
||||
beacon_committee = spec.get_beacon_committee(
|
||||
state,
|
||||
@ -195,7 +196,7 @@ def add_attestations_to_state(spec, state, attestations, slot):
|
||||
spec.process_attestation(state, attestation)
|
||||
|
||||
|
||||
def get_valid_attestation_at_slot(state, spec, slot_to_attest, participation_fn=None):
|
||||
def get_valid_attestation_at_slot(state, spec, slot_to_attest, participation_fn=None, beacon_block_root=None):
|
||||
committees_per_slot = spec.get_committee_count_per_slot(state, spec.compute_epoch_at_slot(slot_to_attest))
|
||||
for index in range(committees_per_slot):
|
||||
def participants_filter(comm):
|
||||
@ -210,7 +211,8 @@ def get_valid_attestation_at_slot(state, spec, slot_to_attest, participation_fn=
|
||||
slot_to_attest,
|
||||
index=index,
|
||||
signed=True,
|
||||
filter_participant_set=participants_filter
|
||||
filter_participant_set=participants_filter,
|
||||
beacon_block_root=beacon_block_root,
|
||||
)
|
||||
|
||||
|
||||
|
@ -92,14 +92,11 @@ def add_attestations(spec, store, attestations, test_steps, is_from_block=False)
|
||||
|
||||
|
||||
def tick_and_run_on_attestation(spec, store, attestation, test_steps, is_from_block=False):
|
||||
parent_block = store.blocks[attestation.data.beacon_block_root]
|
||||
pre_state = store.block_states[spec.hash_tree_root(parent_block)]
|
||||
block_time = pre_state.genesis_time + parent_block.slot * spec.config.SECONDS_PER_SLOT
|
||||
next_epoch_time = block_time + spec.SLOTS_PER_EPOCH * spec.config.SECONDS_PER_SLOT
|
||||
|
||||
if store.time < next_epoch_time:
|
||||
spec.on_tick(store, next_epoch_time)
|
||||
test_steps.append({'tick': int(next_epoch_time)})
|
||||
# Make get_current_slot(store) >= attestation.data.slot + 1
|
||||
min_time_to_include = (attestation.data.slot + 1) * spec.config.SECONDS_PER_SLOT
|
||||
if store.time < min_time_to_include:
|
||||
spec.on_tick(store, min_time_to_include)
|
||||
test_steps.append({'tick': int(min_time_to_include)})
|
||||
|
||||
yield from add_attestation(spec, store, attestation, test_steps, is_from_block)
|
||||
|
||||
|
@ -0,0 +1,154 @@
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_altair_and_later,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
get_valid_attestation_at_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
apply_next_epoch_with_attestations,
|
||||
apply_next_slots_with_attestations,
|
||||
get_genesis_forkchoice_store_and_block,
|
||||
on_tick_and_append_step,
|
||||
tick_and_add_block,
|
||||
tick_and_run_on_attestation,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
next_epoch,
|
||||
next_slot,
|
||||
state_transition_and_sign_block,
|
||||
)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_basic_is_head_root(spec, state):
|
||||
test_steps = []
|
||||
# Initialization
|
||||
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||
yield 'anchor_state', state
|
||||
yield 'anchor_block', anchor_block
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
assert spec.get_head(store) == signed_block.message.hash_tree_root()
|
||||
|
||||
# Proposer of next slot
|
||||
head_root = spec.get_head(store)
|
||||
|
||||
# Proposing next slot
|
||||
next_slot(spec, state)
|
||||
slot = state.slot
|
||||
|
||||
current_time = slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
proposer_head = spec.get_proposer_head(store, head_root, slot)
|
||||
|
||||
assert proposer_head == head_root
|
||||
|
||||
yield 'steps', test_steps
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_basic_is_parent_root(spec, state):
|
||||
test_steps = []
|
||||
# Initialization
|
||||
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||
yield 'anchor_state', state
|
||||
yield 'anchor_block', anchor_block
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
next_epoch(spec, state)
|
||||
on_tick_and_append_step(spec, store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT, test_steps)
|
||||
|
||||
# Fill epoch 1 to 3
|
||||
for _ in range(3):
|
||||
state, store, _ = yield from apply_next_epoch_with_attestations(
|
||||
spec, state, store, True, True, test_steps=test_steps)
|
||||
|
||||
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == 4
|
||||
assert state.current_justified_checkpoint.epoch == store.justified_checkpoint.epoch == 3
|
||||
assert state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 2
|
||||
|
||||
# Make an empty block
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
|
||||
# Fill a slot (parent)
|
||||
state, store, signed_parent_block = yield from apply_next_slots_with_attestations(
|
||||
spec, state, store, 1, True, True, test_steps)
|
||||
|
||||
# Fill a slot with attestations to its parent
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
parent_block_slot = block.slot - 1
|
||||
block.body.attestations = get_valid_attestation_at_slot(
|
||||
state,
|
||||
spec,
|
||||
parent_block_slot,
|
||||
)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
# Make the head block late
|
||||
attesting_cutoff = spec.config.SECONDS_PER_SLOT // spec.INTERVALS_PER_SLOT
|
||||
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time + attesting_cutoff
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
assert store.time == current_time
|
||||
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
|
||||
# Check conditions
|
||||
head_root = spec.get_head(store)
|
||||
head_block = store.blocks[head_root]
|
||||
parent_root = head_block.parent_root
|
||||
assert parent_root == signed_parent_block.message.hash_tree_root()
|
||||
parent_block = store.blocks[parent_root]
|
||||
|
||||
# Proposing next slot
|
||||
next_slot(spec, state)
|
||||
slot = state.slot
|
||||
|
||||
# Add attestations to the parent block
|
||||
current_time = slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||
attestations = get_valid_attestation_at_slot(
|
||||
state,
|
||||
spec,
|
||||
slot_to_attest=slot - 1,
|
||||
beacon_block_root=parent_root,
|
||||
)
|
||||
for attestation in attestations:
|
||||
yield from tick_and_run_on_attestation(spec, store, attestation, test_steps)
|
||||
|
||||
# The conditions in `get_proposer_head`
|
||||
assert spec.is_head_late(store, head_root)
|
||||
assert spec.is_shuffling_stable(slot)
|
||||
assert spec.is_ffg_competitive(store, head_root, parent_root)
|
||||
assert spec.is_finalization_ok(store, slot)
|
||||
assert spec.is_proposing_on_time(store)
|
||||
|
||||
parent_slot_ok = parent_block.slot + 1 == head_block.slot
|
||||
current_time_ok = head_block.slot + 1 == slot
|
||||
single_slot_reorg = parent_slot_ok and current_time_ok
|
||||
assert single_slot_reorg
|
||||
|
||||
assert spec.is_head_weak(store, head_root)
|
||||
assert spec.is_parent_strong(store, parent_root)
|
||||
|
||||
proposer_head = spec.get_proposer_head(store, head_root, state.slot)
|
||||
assert proposer_head == parent_root
|
||||
|
||||
# TODO: export the `proposer_head` result to test vectors?
|
||||
|
||||
yield 'steps', test_steps
|
Loading…
x
Reference in New Issue
Block a user