diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index 3d1e70ca4..9a0657081 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -83,7 +83,6 @@ class Store(Container): def get_genesis_store(genesis_state: BeaconState) -> Store: genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state)) root = signing_root(genesis_block) - print('groot', root) return Store(blocks={root: genesis_block}, states={root: genesis_state}, finalized_root=root, justified_root=root) ``` @@ -91,7 +90,6 @@ def get_genesis_store(genesis_state: BeaconState) -> Store: ```python def get_ancestor(store: Store, root: Bytes32, slot: Slot) -> Bytes32: - print('ruut', root) block = store.blocks[root] assert block.slot >= slot return root if block.slot == slot else get_ancestor(store, block.parent_root, slot) @@ -137,17 +135,14 @@ def on_tick(store: Store, time: int) -> None: ```python def on_block(store: Store, block: BeaconBlock) -> None: # Add new block to the store - print('setting', signing_root(block)) store.blocks[signing_root(block)] = block # Check block is a descendant of the finalized block assert get_ancestor(store, signing_root(block), store.blocks[store.finalized_root].slot) == store.finalized_root # Check block slot against Unix time pre_state = store.states[block.parent_root].copy() - print('store.states[block.parent_root]', hash_tree_root(store.states[block.parent_root])) assert store.time >= pre_state.genesis_time + block.slot * SECONDS_PER_SLOT # Check the block is valid and compute the post-state state = state_transition(pre_state, block) - print('store.states[block.parent_root]', hash_tree_root(store.states[block.parent_root])) # Add new state to the store store.states[signing_root(block)] = state # Update justified and finalized blocks diff --git a/test_libs/pyspec/eth2spec/test/test_finality.py b/test_libs/pyspec/eth2spec/test/test_finality.py index 9556abbd1..801e8b4fd 100644 --- a/test_libs/pyspec/eth2spec/test/test_finality.py +++ b/test_libs/pyspec/eth2spec/test/test_finality.py @@ -1,203 +1,203 @@ -# from copy import deepcopy -# from typing import List +from copy import deepcopy +from typing import List -# from eth2spec.test.context import spec_state_test, never_bls, with_all_phases -# from eth2spec.test.helpers.state import next_epoch -# from eth2spec.test.helpers.block import build_empty_block_for_next_slot, apply_empty_block -# from eth2spec.test.helpers.attestations import get_valid_attestation +from eth2spec.test.context import spec_state_test, never_bls, with_all_phases +from eth2spec.test.helpers.state import next_epoch +from eth2spec.test.helpers.block import build_empty_block_for_next_slot, apply_empty_block +from eth2spec.test.helpers.attestations import get_valid_attestation -# def check_finality(spec, -# state, -# prev_state, -# current_justified_changed, -# previous_justified_changed, -# finalized_changed): -# if current_justified_changed: -# assert state.current_justified_epoch > prev_state.current_justified_epoch -# assert state.current_justified_root != prev_state.current_justified_root -# else: -# assert state.current_justified_epoch == prev_state.current_justified_epoch -# assert state.current_justified_root == prev_state.current_justified_root +def check_finality(spec, + state, + prev_state, + current_justified_changed, + previous_justified_changed, + finalized_changed): + if current_justified_changed: + assert state.current_justified_epoch > prev_state.current_justified_epoch + assert state.current_justified_root != prev_state.current_justified_root + else: + assert state.current_justified_epoch == prev_state.current_justified_epoch + assert state.current_justified_root == prev_state.current_justified_root -# if previous_justified_changed: -# assert state.previous_justified_epoch > prev_state.previous_justified_epoch -# assert state.previous_justified_root != prev_state.previous_justified_root -# else: -# assert state.previous_justified_epoch == prev_state.previous_justified_epoch -# assert state.previous_justified_root == prev_state.previous_justified_root + if previous_justified_changed: + assert state.previous_justified_epoch > prev_state.previous_justified_epoch + assert state.previous_justified_root != prev_state.previous_justified_root + else: + assert state.previous_justified_epoch == prev_state.previous_justified_epoch + assert state.previous_justified_root == prev_state.previous_justified_root -# if finalized_changed: -# assert state.finalized_epoch > prev_state.finalized_epoch -# assert state.finalized_root != prev_state.finalized_root -# else: -# assert state.finalized_epoch == prev_state.finalized_epoch -# assert state.finalized_root == prev_state.finalized_root + if finalized_changed: + assert state.finalized_epoch > prev_state.finalized_epoch + assert state.finalized_root != prev_state.finalized_root + else: + assert state.finalized_epoch == prev_state.finalized_epoch + assert state.finalized_root == prev_state.finalized_root -# def next_epoch_with_attestations(spec, -# state, -# fill_cur_epoch, -# fill_prev_epoch): -# post_state = deepcopy(state) -# blocks = [] -# for _ in range(spec.SLOTS_PER_EPOCH): -# block = build_empty_block_for_next_slot(spec, post_state) -# if fill_cur_epoch: -# slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 -# if slot_to_attest >= spec.get_epoch_start_slot(spec.get_current_epoch(post_state)): -# cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest) -# block.body.attestations.append(cur_attestation) +def next_epoch_with_attestations(spec, + state, + fill_cur_epoch, + fill_prev_epoch): + post_state = deepcopy(state) + blocks = [] + for _ in range(spec.SLOTS_PER_EPOCH): + block = build_empty_block_for_next_slot(spec, post_state) + if fill_cur_epoch: + slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + if slot_to_attest >= spec.get_epoch_start_slot(spec.get_current_epoch(post_state)): + cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest) + block.body.attestations.append(cur_attestation) -# if fill_prev_epoch: -# slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 -# prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest) -# block.body.attestations.append(prev_attestation) + if fill_prev_epoch: + slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 + prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest) + block.body.attestations.append(prev_attestation) -# spec.state_transition(post_state, block) -# blocks.append(block) + spec.state_transition(post_state, block) + blocks.append(block) -# return state, blocks, post_state + return state, blocks, post_state -# @with_all_phases -# @never_bls -# @spec_state_test -# def test_finality_rule_4(spec, state): -# yield 'pre', state +@with_all_phases +@never_bls +@spec_state_test +def test_finality_rule_4(spec, state): + yield 'pre', state -# blocks = [] -# for epoch in range(4): -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) -# blocks += new_blocks + blocks = [] + for epoch in range(4): + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) + blocks += new_blocks -# # justification/finalization skipped at GENESIS_EPOCH -# if epoch == 0: -# check_finality(spec, state, prev_state, False, False, False) -# # justification/finalization skipped at GENESIS_EPOCH + 1 -# elif epoch == 1: -# check_finality(spec, state, prev_state, False, False, False) -# elif epoch == 2: -# check_finality(spec, state, prev_state, True, False, False) -# elif epoch >= 3: -# # rule 4 of finality -# check_finality(spec, state, prev_state, True, True, True) -# assert state.finalized_epoch == prev_state.current_justified_epoch -# assert state.finalized_root == prev_state.current_justified_root + # justification/finalization skipped at GENESIS_EPOCH + if epoch == 0: + check_finality(spec, state, prev_state, False, False, False) + # justification/finalization skipped at GENESIS_EPOCH + 1 + elif epoch == 1: + check_finality(spec, state, prev_state, False, False, False) + elif epoch == 2: + check_finality(spec, state, prev_state, True, False, False) + elif epoch >= 3: + # rule 4 of finality + check_finality(spec, state, prev_state, True, True, True) + assert state.finalized_epoch == prev_state.current_justified_epoch + assert state.finalized_root == prev_state.current_justified_root -# yield 'blocks', blocks, List[spec.BeaconBlock] -# yield 'post', state + yield 'blocks', blocks, List[spec.BeaconBlock] + yield 'post', state -# @with_all_phases -# @never_bls -# @spec_state_test -# def test_finality_rule_1(spec, state): -# # get past first two epochs that finality does not run on -# next_epoch(spec, state) -# apply_empty_block(spec, state) -# next_epoch(spec, state) -# apply_empty_block(spec, state) +@with_all_phases +@never_bls +@spec_state_test +def test_finality_rule_1(spec, state): + # get past first two epochs that finality does not run on + next_epoch(spec, state) + apply_empty_block(spec, state) + next_epoch(spec, state) + apply_empty_block(spec, state) -# yield 'pre', state + yield 'pre', state -# blocks = [] -# for epoch in range(3): -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) -# blocks += new_blocks + blocks = [] + for epoch in range(3): + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) + blocks += new_blocks -# if epoch == 0: -# check_finality(spec, state, prev_state, True, False, False) -# elif epoch == 1: -# check_finality(spec, state, prev_state, True, True, False) -# elif epoch == 2: -# # finalized by rule 1 -# check_finality(spec, state, prev_state, True, True, True) -# assert state.finalized_epoch == prev_state.previous_justified_epoch -# assert state.finalized_root == prev_state.previous_justified_root + if epoch == 0: + check_finality(spec, state, prev_state, True, False, False) + elif epoch == 1: + check_finality(spec, state, prev_state, True, True, False) + elif epoch == 2: + # finalized by rule 1 + check_finality(spec, state, prev_state, True, True, True) + assert state.finalized_epoch == prev_state.previous_justified_epoch + assert state.finalized_root == prev_state.previous_justified_root -# yield 'blocks', blocks, List[spec.BeaconBlock] -# yield 'post', state + yield 'blocks', blocks, List[spec.BeaconBlock] + yield 'post', state -# @with_all_phases -# @never_bls -# @spec_state_test -# def test_finality_rule_2(spec, state): -# # get past first two epochs that finality does not run on -# next_epoch(spec, state) -# apply_empty_block(spec, state) -# next_epoch(spec, state) -# apply_empty_block(spec, state) +@with_all_phases +@never_bls +@spec_state_test +def test_finality_rule_2(spec, state): + # get past first two epochs that finality does not run on + next_epoch(spec, state) + apply_empty_block(spec, state) + next_epoch(spec, state) + apply_empty_block(spec, state) -# yield 'pre', state + yield 'pre', state -# blocks = [] -# for epoch in range(3): -# if epoch == 0: -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) -# check_finality(spec, state, prev_state, True, False, False) -# elif epoch == 1: -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, False) -# check_finality(spec, state, prev_state, False, True, False) -# elif epoch == 2: -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) -# # finalized by rule 2 -# check_finality(spec, state, prev_state, True, False, True) -# assert state.finalized_epoch == prev_state.previous_justified_epoch -# assert state.finalized_root == prev_state.previous_justified_root + blocks = [] + for epoch in range(3): + if epoch == 0: + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) + check_finality(spec, state, prev_state, True, False, False) + elif epoch == 1: + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, False) + check_finality(spec, state, prev_state, False, True, False) + elif epoch == 2: + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) + # finalized by rule 2 + check_finality(spec, state, prev_state, True, False, True) + assert state.finalized_epoch == prev_state.previous_justified_epoch + assert state.finalized_root == prev_state.previous_justified_root -# blocks += new_blocks + blocks += new_blocks -# yield 'blocks', blocks, List[spec.BeaconBlock] -# yield 'post', state + yield 'blocks', blocks, List[spec.BeaconBlock] + yield 'post', state -# @with_all_phases -# @never_bls -# @spec_state_test -# def test_finality_rule_3(spec, state): -# """ -# Test scenario described here -# https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892 -# """ -# # get past first two epochs that finality does not run on -# next_epoch(spec, state) -# apply_empty_block(spec, state) -# next_epoch(spec, state) -# apply_empty_block(spec, state) +@with_all_phases +@never_bls +@spec_state_test +def test_finality_rule_3(spec, state): + """ + Test scenario described here + https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892 + """ + # get past first two epochs that finality does not run on + next_epoch(spec, state) + apply_empty_block(spec, state) + next_epoch(spec, state) + apply_empty_block(spec, state) -# yield 'pre', state + yield 'pre', state -# blocks = [] -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) -# blocks += new_blocks -# check_finality(spec, state, prev_state, True, False, False) + blocks = [] + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) + blocks += new_blocks + check_finality(spec, state, prev_state, True, False, False) -# # In epoch N, JE is set to N, prev JE is set to N-1 -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) -# blocks += new_blocks -# check_finality(spec, state, prev_state, True, True, True) + # In epoch N, JE is set to N, prev JE is set to N-1 + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, False) + blocks += new_blocks + check_finality(spec, state, prev_state, True, True, True) -# # In epoch N+1, JE is N, prev JE is N-1, and not enough messages get in to do anything -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, False) -# blocks += new_blocks -# check_finality(spec, state, prev_state, False, True, False) + # In epoch N+1, JE is N, prev JE is N-1, and not enough messages get in to do anything + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, False) + blocks += new_blocks + check_finality(spec, state, prev_state, False, True, False) -# # In epoch N+2, JE is N, prev JE is N, and enough messages from the previous epoch get in to justify N+1. -# # N+1 now becomes the JE. Not enough messages from epoch N+2 itself get in to justify N+2 -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) -# blocks += new_blocks -# # rule 2 -# check_finality(spec, state, prev_state, True, False, True) + # In epoch N+2, JE is N, prev JE is N, and enough messages from the previous epoch get in to justify N+1. + # N+1 now becomes the JE. Not enough messages from epoch N+2 itself get in to justify N+2 + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) + blocks += new_blocks + # rule 2 + check_finality(spec, state, prev_state, True, False, True) -# # In epoch N+3, LJE is N+1, prev LJE is N, and enough messages get in to justify epochs N+2 and N+3. -# prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, True) -# blocks += new_blocks -# # rule 3 -# check_finality(spec, state, prev_state, True, True, True) -# assert state.finalized_epoch == prev_state.current_justified_epoch -# assert state.finalized_root == prev_state.current_justified_root + # In epoch N+3, LJE is N+1, prev LJE is N, and enough messages get in to justify epochs N+2 and N+3. + prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, True, True) + blocks += new_blocks + # rule 3 + check_finality(spec, state, prev_state, True, True, True) + assert state.finalized_epoch == prev_state.current_justified_epoch + assert state.finalized_root == prev_state.current_justified_root -# yield 'blocks', blocks, List[spec.BeaconBlock] -# yield 'post', state + yield 'blocks', blocks, List[spec.BeaconBlock] + yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/test_fork_choice.py b/test_libs/pyspec/eth2spec/test/test_fork_choice.py index c1df605fe..6f054fc52 100644 --- a/test_libs/pyspec/eth2spec/test/test_fork_choice.py +++ b/test_libs/pyspec/eth2spec/test/test_fork_choice.py @@ -1,4 +1,6 @@ -from eth2spec.utils.ssz.ssz_impl import signing_root +from typing import List + +from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root from eth2spec.test.context import with_all_phases, spec_state_test @@ -10,6 +12,7 @@ from eth2spec.test.helpers.state import next_slot @with_all_phases @spec_state_test def test_basic(spec, state): + state.latest_block_header = spec.BeaconBlockHeader(body_root=hash_tree_root(spec.BeaconBlockBody())) yield 'pre', state # Initialization diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 5b3500d3e..7df95d119 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -133,7 +133,7 @@ class Container(object): return [getattr(self, field) for field in cls.get_field_names()] def copy(self): - return self.deepcopy(self) + return copy.deepcopy(self) def __repr__(self): return repr({field: getattr(self, field) for field in self.get_field_names()})