Add `test_new_justified_is_later_than_store_justified` and fix test
cases - Fix `on_tick` calls - Refactor test cases
This commit is contained in:
parent
7a9ae57335
commit
83598af188
|
@ -261,6 +261,38 @@ def next_epoch_with_attestations(spec,
|
|||
)
|
||||
|
||||
|
||||
def state_transition_with_signed_full_block(spec, state, fill_cur_epoch, fill_prev_epoch):
|
||||
# Build a block with previous attestations
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
attestations = []
|
||||
|
||||
if fill_prev_epoch:
|
||||
# current epoch
|
||||
slots = state.slot % spec.SLOTS_PER_EPOCH
|
||||
for slot_offset in range(slots):
|
||||
target_slot = state.slot - slot_offset
|
||||
attestations += _get_valid_attestation_at_slot(
|
||||
state,
|
||||
spec,
|
||||
target_slot,
|
||||
)
|
||||
|
||||
if fill_prev_epoch:
|
||||
# attest previous epoch
|
||||
slots = spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH
|
||||
for slot_offset in range(1, slots):
|
||||
target_slot = state.slot - (state.slot % spec.SLOTS_PER_EPOCH) - slot_offset
|
||||
attestations += _get_valid_attestation_at_slot(
|
||||
state,
|
||||
spec,
|
||||
target_slot,
|
||||
)
|
||||
|
||||
block.body.attestations = attestations
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
return signed_block
|
||||
|
||||
|
||||
def prepare_state_with_attestations(spec, state, participation_fn=None):
|
||||
"""
|
||||
Prepare state with attestations according to the ``participation_fn``.
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
from copy import deepcopy
|
||||
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
|
||||
|
||||
from eth2spec.test.context import with_all_phases, spec_state_test
|
||||
from eth2spec.test.helpers.attestations import next_epoch_with_attestations
|
||||
from eth2spec.test.context import MINIMAL, with_all_phases, spec_state_test, with_presets
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
next_epoch_with_attestations,
|
||||
next_slots_with_attestations,
|
||||
state_transition_with_signed_full_block,
|
||||
)
|
||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, transition_unsigned_block, \
|
||||
build_empty_block, sign_block
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
|
@ -10,7 +14,7 @@ from eth2spec.test.helpers.fork_choice import (
|
|||
run_on_block,
|
||||
apply_next_epoch_with_attestations,
|
||||
)
|
||||
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block, transition_to
|
||||
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block, transition_to, next_slots
|
||||
|
||||
|
||||
@with_all_phases
|
||||
|
@ -48,7 +52,7 @@ def test_on_block_finalized_skip_slots(spec, state):
|
|||
# Build block that includes the skipped slots up to finality in chain
|
||||
block = build_empty_block(spec, state, spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, signed_block)
|
||||
|
||||
|
||||
|
@ -81,7 +85,7 @@ def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state):
|
|||
slot=spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2)
|
||||
signed_block = sign_block(spec, pre_state, block)
|
||||
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, signed_block, valid=False)
|
||||
|
||||
|
||||
|
@ -94,10 +98,10 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
|
|||
spec.on_tick(store, time)
|
||||
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
state, store, last_signed_block = yield from apply_next_epoch_with_attestations(spec, state, store)
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
last_block = last_signed_block.message
|
||||
last_block_root = last_block.hash_tree_root()
|
||||
|
||||
|
@ -137,7 +141,7 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
|
|||
spec.on_tick(store, time)
|
||||
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
state, store, last_signed_block = yield from apply_next_epoch_with_attestations(spec, state, store)
|
||||
last_block_root = hash_tree_root(last_signed_block.message)
|
||||
|
||||
|
@ -148,7 +152,7 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
|
|||
)
|
||||
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
|
||||
# Create new higher justified checkpoint not in branch of store's justified checkpoint
|
||||
just_block = build_empty_block_for_next_slot(spec, state)
|
||||
|
@ -201,7 +205,7 @@ def test_on_block_outside_safe_slots_but_finality(spec, state):
|
|||
spec.on_tick(store, time)
|
||||
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
state, store, last_signed_block = yield from apply_next_epoch_with_attestations(spec, state, store)
|
||||
last_block_root = hash_tree_root(last_signed_block.message)
|
||||
|
||||
|
@ -212,7 +216,7 @@ def test_on_block_outside_safe_slots_but_finality(spec, state):
|
|||
)
|
||||
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
|
||||
# NOTE: Mock a new higher justified checkpoint not in branch of store's justified checkpoint
|
||||
just_block = build_empty_block_for_next_slot(spec, state)
|
||||
|
@ -255,18 +259,166 @@ def test_on_block_outside_safe_slots_but_finality(spec, state):
|
|||
assert store.justified_checkpoint == new_justified
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_presets([MINIMAL], reason="It assumes that `MAX_ATTESTATIONS` >= 2/3 attestations of an epoch")
|
||||
@spec_state_test
|
||||
def test_new_justified_is_later_than_store_justified(spec, state):
|
||||
"""
|
||||
J: Justified
|
||||
F: Finalized
|
||||
fork_1_state (forked from genesis):
|
||||
epoch
|
||||
[0] <- [1] <- [2] <- [3] <- [4]
|
||||
F J
|
||||
|
||||
fork_2_state (forked from fork_1_state's epoch 2):
|
||||
epoch
|
||||
└──── [3] <- [4] <- [5] <- [6]
|
||||
F J
|
||||
|
||||
fork_3_state (forked from genesis):
|
||||
[0] <- [1] <- [2] <- [3] <- [4] <- [5]
|
||||
F J
|
||||
"""
|
||||
# The 1st fork, from genesis
|
||||
fork_1_state = state.copy()
|
||||
# The 3rd fork, from genesis
|
||||
fork_3_state = state.copy()
|
||||
|
||||
# Initialization
|
||||
store = get_genesis_forkchoice_store(spec, fork_1_state)
|
||||
time = 0
|
||||
spec.on_tick(store, time)
|
||||
|
||||
# ----- Process fork_1_state
|
||||
# Skip epoch 0
|
||||
next_epoch(spec, fork_1_state)
|
||||
# Fill epoch 1 with previous epoch attestations
|
||||
_, signed_blocks, fork_1_state = next_epoch_with_attestations(spec, fork_1_state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.genesis_time + fork_1_state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
# Fork `fork_2_state` at the start of epoch 2
|
||||
fork_2_state = fork_1_state.copy()
|
||||
assert spec.get_current_epoch(fork_2_state) == 2
|
||||
|
||||
# Skip epoch 2
|
||||
next_epoch(spec, fork_1_state)
|
||||
# # Fill epoch 3 & 4 with previous epoch attestations
|
||||
for _ in range(2):
|
||||
_, signed_blocks, fork_1_state = next_epoch_with_attestations(spec, fork_1_state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.genesis_time + fork_1_state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
assert fork_1_state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 0
|
||||
assert fork_1_state.current_justified_checkpoint.epoch == store.justified_checkpoint.epoch == 3
|
||||
assert store.justified_checkpoint.hash_tree_root() == fork_1_state.current_justified_checkpoint.hash_tree_root()
|
||||
|
||||
# ------ fork_2_state: Create a chain to set store.best_justified_checkpoint
|
||||
# NOTE: The goal is to make `store.best_justified_checkpoint.epoch > store.justified_checkpoint.epoch`
|
||||
all_blocks = []
|
||||
|
||||
# Proposed an empty block at epoch 2, 1st slot
|
||||
block = build_empty_block_for_next_slot(spec, fork_2_state)
|
||||
signed_block = state_transition_and_sign_block(spec, fork_2_state, block)
|
||||
all_blocks.append(signed_block.copy())
|
||||
assert fork_2_state.current_justified_checkpoint.epoch == 0
|
||||
|
||||
# Skip to epoch 4
|
||||
for _ in range(2):
|
||||
next_epoch(spec, fork_2_state)
|
||||
assert fork_2_state.current_justified_checkpoint.epoch == 0
|
||||
|
||||
# Propose a block at epoch 4, 5th slot
|
||||
# Propose a block at epoch 5, 5th slot
|
||||
for _ in range(2):
|
||||
next_epoch(spec, fork_2_state)
|
||||
next_slots(spec, fork_2_state, 4)
|
||||
signed_block = state_transition_with_signed_full_block(spec, fork_2_state, True, True)
|
||||
all_blocks.append(signed_block.copy())
|
||||
assert fork_2_state.current_justified_checkpoint.epoch == 0
|
||||
|
||||
# Propose a block at epoch 6, SAFE_SLOTS_TO_UPDATE_JUSTIFIED + 2 slot
|
||||
next_epoch(spec, fork_2_state)
|
||||
next_slots(spec, fork_2_state, spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED + 2)
|
||||
signed_block = state_transition_with_signed_full_block(spec, fork_2_state, True, True)
|
||||
all_blocks.append(signed_block.copy())
|
||||
assert fork_2_state.finalized_checkpoint.epoch == 0
|
||||
assert fork_2_state.current_justified_checkpoint.epoch == 5
|
||||
|
||||
# Check SAFE_SLOTS_TO_UPDATE_JUSTIFIED
|
||||
spec.on_tick(store, store.genesis_time + fork_2_state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
assert spec.compute_slots_since_epoch_start(spec.get_current_slot(store)) >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED
|
||||
|
||||
# Apply blocks of `fork_3_state` to `store`
|
||||
for block in all_blocks:
|
||||
if store.time < spec.compute_time_at_slot(fork_2_state, block.message.slot):
|
||||
spec.on_tick(store, store.genesis_time + block.message.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
assert store.finalized_checkpoint.epoch == 0
|
||||
assert store.justified_checkpoint.epoch == 3
|
||||
assert store.best_justified_checkpoint.epoch == 5
|
||||
|
||||
# ------ fork_3_state: Create another chain to test the
|
||||
# "Update justified if new justified is later than store justified" case
|
||||
all_blocks = []
|
||||
for _ in range(3):
|
||||
next_epoch(spec, fork_3_state)
|
||||
|
||||
# epoch 3
|
||||
_, signed_blocks, fork_3_state = next_epoch_with_attestations(spec, fork_3_state, True, True)
|
||||
all_blocks += signed_blocks
|
||||
assert fork_3_state.finalized_checkpoint.epoch == 0
|
||||
|
||||
# epoch 4, attest the first 5 blocks
|
||||
_, blocks, fork_3_state = next_slots_with_attestations(spec, fork_3_state, 5, True, True)
|
||||
all_blocks += blocks.copy()
|
||||
assert fork_3_state.finalized_checkpoint.epoch == 0
|
||||
|
||||
# Propose a block at epoch 5, 5th slot
|
||||
next_epoch(spec, fork_3_state)
|
||||
next_slots(spec, fork_3_state, 4)
|
||||
signed_block = state_transition_with_signed_full_block(spec, fork_3_state, True, True)
|
||||
all_blocks.append(signed_block.copy())
|
||||
assert fork_3_state.finalized_checkpoint.epoch == 0
|
||||
|
||||
# Propose a block at epoch 6, 5th slot
|
||||
next_epoch(spec, fork_3_state)
|
||||
next_slots(spec, fork_3_state, 4)
|
||||
signed_block = state_transition_with_signed_full_block(spec, fork_3_state, True, True)
|
||||
all_blocks.append(signed_block.copy())
|
||||
assert fork_3_state.finalized_checkpoint.epoch == 3
|
||||
assert fork_3_state.current_justified_checkpoint.epoch == 4
|
||||
|
||||
# Apply blocks of `fork_3_state` to `store`
|
||||
for block in all_blocks:
|
||||
if store.time < spec.compute_time_at_slot(fork_2_state, block.message.slot):
|
||||
spec.on_tick(store, store.genesis_time + block.message.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
assert store.finalized_checkpoint.hash_tree_root() == fork_3_state.finalized_checkpoint.hash_tree_root()
|
||||
assert (store.justified_checkpoint.hash_tree_root()
|
||||
== fork_3_state.current_justified_checkpoint.hash_tree_root()
|
||||
!= store.best_justified_checkpoint.hash_tree_root())
|
||||
assert (store.best_justified_checkpoint.hash_tree_root()
|
||||
== fork_2_state.current_justified_checkpoint.hash_tree_root())
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
|
||||
"""
|
||||
J: Justified
|
||||
F: Finalized
|
||||
pre-store:
|
||||
state (forked from genesis):
|
||||
epoch
|
||||
[0] <- [1] <- [2] <- [3] <- [4] <- [5]
|
||||
F J
|
||||
|
||||
another_state:
|
||||
another_state (forked from genesis):
|
||||
[0] <- [1] <- [2] <- [3] <- [4] <- [5]
|
||||
F J
|
||||
"""
|
||||
|
@ -276,17 +428,22 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
|
|||
time = 0
|
||||
spec.on_tick(store, time)
|
||||
|
||||
# Process state
|
||||
# ----- Process state
|
||||
# Goal: make `store.finalized_checkpoint.epoch == 0` and `store.justified_checkpoint.epoch == 3`
|
||||
# Skip epoch 0
|
||||
next_epoch(spec, state)
|
||||
# Fill epoch 1 with previous epoch attestations
|
||||
_, signed_blocks, state = next_epoch_with_attestations(spec, state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
# Skip epoch 2
|
||||
next_epoch(spec, state)
|
||||
# Fill epoch 3 & 4 with previous epoch attestations
|
||||
for _ in range(2):
|
||||
_, signed_blocks, state = next_epoch_with_attestations(spec, state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
assert state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 0
|
||||
|
@ -294,11 +451,11 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
|
|||
assert store.justified_checkpoint.hash_tree_root() == state.current_justified_checkpoint.hash_tree_root()
|
||||
|
||||
# Create another chain
|
||||
# another_state = store.block_states[store.justified_checkpoint.root].copy()
|
||||
next_epoch(spec, another_state)
|
||||
spec.on_tick(store, store.time + another_state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
|
||||
# Goal: make `another_state.finalized_checkpoint.epoch == 2` and `another_state.justified_checkpoint.epoch == 3`
|
||||
all_blocks = []
|
||||
# Skip epoch 0
|
||||
next_epoch(spec, another_state)
|
||||
# Fill epoch 1 & 2 with previous + current epoch attestations
|
||||
for _ in range(3):
|
||||
_, signed_blocks, another_state = next_epoch_with_attestations(spec, another_state, True, True)
|
||||
all_blocks += signed_blocks
|
||||
|
@ -310,9 +467,11 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
|
|||
state.current_justified_checkpoint.hash_tree_root()
|
||||
!= another_state.current_justified_checkpoint.hash_tree_root()
|
||||
)
|
||||
|
||||
pre_store_justified_checkpoint_root = store.justified_checkpoint.root
|
||||
|
||||
# Apply blocks of `another_state` to `store`
|
||||
for block in all_blocks:
|
||||
# NOTE: Do not call `on_tick` here
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
|
@ -329,14 +488,14 @@ def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
|
|||
"""
|
||||
J: Justified
|
||||
F: Finalized
|
||||
pre-store:
|
||||
state:
|
||||
epoch
|
||||
[0] <- [1] <- [2] <- [3] <- [4] <- [5]
|
||||
F J
|
||||
|
||||
another_state:
|
||||
<- [4] <- [5]
|
||||
F+J
|
||||
another_state (forked from state at epoch 3):
|
||||
└──── [4] <- [5]
|
||||
F J
|
||||
"""
|
||||
# Initialization
|
||||
store = get_genesis_forkchoice_store(spec, state)
|
||||
|
@ -345,21 +504,21 @@ def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
|
|||
|
||||
# Process state
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
_, signed_blocks, state = next_epoch_with_attestations(spec, state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
_, signed_blocks, state = next_epoch_with_attestations(spec, state, True, False)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
next_epoch(spec, state)
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
for _ in range(2):
|
||||
_, signed_blocks, state = next_epoch_with_attestations(spec, state, False, True)
|
||||
for block in signed_blocks:
|
||||
spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
spec.on_tick(store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
assert state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 2
|
||||
|
@ -381,6 +540,8 @@ def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
|
|||
|
||||
pre_store_justified_checkpoint_root = store.justified_checkpoint.root
|
||||
for block in all_blocks:
|
||||
if store.time < spec.compute_time_at_slot(another_state, block.message.slot):
|
||||
spec.on_tick(store, store.genesis_time + block.message.slot * spec.config.SECONDS_PER_SLOT)
|
||||
run_on_block(spec, store, block)
|
||||
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
|
|
Loading…
Reference in New Issue