diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index c840179b9..3ed794584 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -163,5 +163,8 @@ def on_attestation(store: Store, attestation: Attestation) -> None: validate_indexed_attestation(state, indexed_attestation) for i in indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices: if i not in store.latest_targets or attestation.data.target_epoch > store.latest_targets[i].epoch: - store.latest_targets[i] = Target(attestation.data.target_epoch, attestation.data.target_root) + store.latest_targets[i] = Target( + epoch = attestation.data.target_epoch, + root = attestation.data.target_root, + ) ``` diff --git a/test_libs/pyspec/eth2spec/test/test_fork_choice.py b/test_libs/pyspec/eth2spec/test/test_fork_choice.py index 46b60b93c..374466032 100644 --- a/test_libs/pyspec/eth2spec/test/test_fork_choice.py +++ b/test_libs/pyspec/eth2spec/test/test_fork_choice.py @@ -10,41 +10,56 @@ from eth2spec.test.helpers.state import next_slot @with_all_phases @spec_state_test def test_basic(spec, state): + yield 'pre', state + # Initialization - store = spec.get_genesis_store(state) - time = 100 - spec.on_tick(store, time) - assert store.time == time + store = spec.get_genesis_store(state) + blocks = [] + time = 100 + spec.on_tick(store, time) + assert store.time == time # On receiving a block of `GENESIS_SLOT + 1` slot - block = build_empty_block_for_next_slot(state) - spec.on_block(store, block) - assert store.blocks[signing_root(block)] == block + block = build_empty_block_for_next_slot(spec, state) + blocks.append(block) + spec.on_block(store, block) + assert store.blocks[signing_root(block)] == block # On receiving a block of next epoch - store.time = time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - block = build_empty_block_for_next_slot(state) - block.slot += spec.SLOTS_PER_EPOCH + store.time = time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + block = build_empty_block_for_next_slot(spec, state) + block.slot += spec.SLOTS_PER_EPOCH + blocks.append(block) - spec.on_block(store, block) - assert store.blocks[signing_root(block)] == block + spec.on_block(store, block) + assert store.blocks[signing_root(block)] == block + yield 'blocks', blocks, List[spec.BeaconBlock] # TODO: add tests for justified_root and finalized_root + yield 'post', state @with_all_phases @spec_state_test def test_on_attestation(spec, state): - store = spec.get_genesis_store(state) - time = 100 - spec.on_tick(store, time) + yield 'pre', state - next_slot(state) + store = spec.get_genesis_store(state) + time = 100 + spec.on_tick(store, time) - attestation = get_valid_attestation(state, slot=1) - indexed_attestation = spec.convert_to_indexed(state, attestation) - spec.on_attestation(store, attestation) - assert ( - store.latest_targets[indexed_attestation.custody_bit_0_indices[0]] == - spec.Target(attestation.data.target_epoch, attestation.data.target_root) - ) \ No newline at end of file + next_slot(spec, state) + + attestation = get_valid_attestation(spec, state, slot=1) + yield 'attestation', attestation + indexed_attestation = spec.convert_to_indexed(state, attestation) + spec.on_attestation(store, attestation) + assert ( + store.latest_targets[indexed_attestation.custody_bit_0_indices[0]] == + spec.Target( + epoch = attestation.data.target_epoch, + root = attestation.data.target_root + ) + ) + + yield 'post', state \ No newline at end of file diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 55ced4ee2..7119f2e5b 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -1,4 +1,4 @@ -from typing import List, Iterable, TypeVar, Type, NewType +from typing import List, Iterable, TypeVar, Type, NewType, Dict from typing import Union from typing_inspect import get_origin @@ -280,6 +280,32 @@ class Vector(metaclass=VectorMeta): return self.hash_tree_root() == other.hash_tree_root() +# # Super Secret Un-documented SSZ Dict (for forkchoice) +# # ----------------------------- +class Dict(dict): + def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs) + + def serialize(self): + raise NotImplementedError + + def hash_tree_root(self): + raise NotImplementedError + + def __getitem__(self, key): + return self.items[key] + + def __setitem__(self, key, value): + self.items[key] = value + + def __iter__(self): + return iter(self.items) + + def __len__(self): + return len(self.items) + + def __eq__(self, other): + raise NotImplementedError + # SSZ BytesN # ----------------------------- @@ -407,6 +433,8 @@ def get_zero_value(typ): return b'' elif is_container_type(typ): return typ(**{f: get_zero_value(t) for f, t in typ.get_fields()}) + elif is_dict_type(typ): + return dict() else: raise Exception("Type not supported: {}".format(typ)) @@ -498,6 +526,13 @@ def is_container_type(typ): return isinstance(typ, type) and issubclass(typ, Container) +def is_dict_type(typ): + """ + Check of the given type is a Dict. (Which are a part of the super-secret undocumented SSZ spec) + """ + return get_origin(typ) is Dict or get_origin(typ) is dict + + T = TypeVar('T') L = TypeVar('L')