Merge branch 'dev' into fork-choice-epoch
This commit is contained in:
commit
74eeb87936
|
@ -25,8 +25,6 @@ from dataclasses import (
|
||||||
field,
|
field,
|
||||||
)
|
)
|
||||||
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from eth2spec.utils.ssz.ssz_impl import (
|
from eth2spec.utils.ssz.ssz_impl import (
|
||||||
hash_tree_root,
|
hash_tree_root,
|
||||||
signing_root,
|
signing_root,
|
||||||
|
@ -60,8 +58,6 @@ from dataclasses import (
|
||||||
field,
|
field,
|
||||||
)
|
)
|
||||||
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from eth2spec.utils.ssz.ssz_impl import (
|
from eth2spec.utils.ssz.ssz_impl import (
|
||||||
hash_tree_root,
|
hash_tree_root,
|
||||||
signing_root,
|
signing_root,
|
||||||
|
|
|
@ -47,10 +47,11 @@ The head block root associated with a `store` is defined as `get_head(store)`. A
|
||||||
|
|
||||||
*Notes*:
|
*Notes*:
|
||||||
|
|
||||||
1) **Leap seconds**: Slots will last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds around leap seconds.
|
1) **Leap seconds**: Slots will last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds around leap seconds. This is automatically handled by [UNIX time](https://en.wikipedia.org/wiki/Unix_time).
|
||||||
2) **Honest clocks**: Honest nodes are assumed to have clocks synchronized within `SECONDS_PER_SLOT` seconds of each other.
|
2) **Honest clocks**: Honest nodes are assumed to have clocks synchronized within `SECONDS_PER_SLOT` seconds of each other.
|
||||||
3) **Eth1 data**: The large `ETH1_FOLLOW_DISTANCE` specified in the [honest validator document](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/validator/0_beacon-chain-validator.md) should ensure that `state.latest_eth1_data` of the canonical Ethereum 2.0 chain remains consistent with the canonical Ethereum 1.0 chain. If not, emergency manual intervention will be required.
|
3) **Eth1 data**: The large `ETH1_FOLLOW_DISTANCE` specified in the [honest validator document](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/validator/0_beacon-chain-validator.md) should ensure that `state.latest_eth1_data` of the canonical Ethereum 2.0 chain remains consistent with the canonical Ethereum 1.0 chain. If not, emergency manual intervention will be required.
|
||||||
4) **Manual forks**: Manual forks may arbitrarily change the fork choice rule but are expected to be enacted at epoch transitions, with the fork details reflected in `state.fork`.
|
4) **Manual forks**: Manual forks may arbitrarily change the fork choice rule but are expected to be enacted at epoch transitions, with the fork details reflected in `state.fork`.
|
||||||
|
5) **Implementation**: The implementation found in this specification is constructed for ease of understanding rather than for optimization in computation, space, or any other resource. A number of optimized alternatives can be found [here](https://github.com/protolambda/lmd-ghost).
|
||||||
|
|
||||||
### Helpers
|
### Helpers
|
||||||
|
|
||||||
|
@ -95,7 +96,13 @@ class Store(object):
|
||||||
def get_genesis_store(genesis_state: BeaconState) -> Store:
|
def get_genesis_store(genesis_state: BeaconState) -> Store:
|
||||||
genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))
|
genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))
|
||||||
root = signing_root(genesis_block)
|
root = signing_root(genesis_block)
|
||||||
return Store(blocks={root: genesis_block}, states={root: genesis_state}, justified_root=root, finalized_root=root)
|
return Store(
|
||||||
|
blocks={root: genesis_block},
|
||||||
|
states={root: genesis_state},
|
||||||
|
time=genesis_state.genesis_time,
|
||||||
|
justified_root=root,
|
||||||
|
finalized_root=root,
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_ancestor`
|
#### `get_ancestor`
|
||||||
|
@ -150,16 +157,17 @@ def on_tick(store: Store, time: int) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def on_block(store: Store, block: BeaconBlock) -> None:
|
def on_block(store: Store, block: BeaconBlock) -> None:
|
||||||
|
# Make a copy of the state to avoid mutability issues
|
||||||
|
parent_block = store.blocks[block.parent_root]
|
||||||
|
pre_state = store.states[RootSlot(signing_root(parent_block), parent_block.slot)].copy()
|
||||||
|
# Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
|
||||||
|
assert store.time >= pre_state.genesis_time + block.slot * SECONDS_PER_SLOT
|
||||||
# Add new block to the store
|
# Add new block to the store
|
||||||
store.blocks[signing_root(block)] = block
|
store.blocks[signing_root(block)] = block
|
||||||
# Check block is a descendant of the finalized 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
|
assert get_ancestor(store, signing_root(block), store.blocks[store.finalized_root].slot) == store.finalized_root
|
||||||
# Check that block is later than the finalized epoch slot
|
# Check that block is later than the finalized epoch slot
|
||||||
assert blocks.slot > get_epoch_start_slot(store.finalized_epoch)
|
assert blocks.slot > get_epoch_start_slot(store.finalized_epoch)
|
||||||
# Check block slot against Unix time
|
|
||||||
parent_block = store.blocks[block.parent_root]
|
|
||||||
pre_state = deepcopy(store.states[RootSlot(signing_root(parent_block), parent_block.slot)])
|
|
||||||
assert store.time >= pre_state.genesis_time + block.slot * SECONDS_PER_SLOT
|
|
||||||
# Check the block is valid and compute the post-state
|
# Check the block is valid and compute the post-state
|
||||||
state = state_transition(pre_state, block)
|
state = state_transition(pre_state, block)
|
||||||
# Add new state for this block to the store
|
# Add new state for this block to the store
|
||||||
|
|
|
@ -2,7 +2,7 @@ from typing import List
|
||||||
|
|
||||||
from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root
|
from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root
|
||||||
|
|
||||||
from eth2spec.test.context import with_all_phases, spec_state_test
|
from eth2spec.test.context import with_all_phases, with_state, bls_switch
|
||||||
|
|
||||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||||
from eth2spec.test.helpers.attestations import get_valid_attestation
|
from eth2spec.test.helpers.attestations import get_valid_attestation
|
||||||
|
@ -10,10 +10,10 @@ from eth2spec.test.helpers.state import next_slot
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@with_state
|
||||||
|
@bls_switch
|
||||||
def test_basic(spec, state):
|
def test_basic(spec, state):
|
||||||
state.latest_block_header = spec.BeaconBlockHeader(body_root=hash_tree_root(spec.BeaconBlockBody()))
|
state.latest_block_header = spec.BeaconBlockHeader(body_root=hash_tree_root(spec.BeaconBlockBody()))
|
||||||
yield 'pre', state
|
|
||||||
|
|
||||||
# Initialization
|
# Initialization
|
||||||
store = spec.get_genesis_store(state)
|
store = spec.get_genesis_store(state)
|
||||||
|
@ -36,17 +36,14 @@ def test_basic(spec, state):
|
||||||
|
|
||||||
spec.on_block(store, block)
|
spec.on_block(store, block)
|
||||||
assert store.blocks[signing_root(block)] == block
|
assert store.blocks[signing_root(block)] == block
|
||||||
yield 'blocks', blocks, List[spec.BeaconBlock]
|
|
||||||
|
|
||||||
# TODO: add tests for justified_root and finalized_root
|
# TODO: add tests for justified_root and finalized_root
|
||||||
yield 'post', state
|
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@with_state
|
||||||
|
@bls_switch
|
||||||
def test_on_attestation(spec, state):
|
def test_on_attestation(spec, state):
|
||||||
yield 'pre', state
|
|
||||||
|
|
||||||
store = spec.get_genesis_store(state)
|
store = spec.get_genesis_store(state)
|
||||||
time = 100
|
time = 100
|
||||||
spec.on_tick(store, time)
|
spec.on_tick(store, time)
|
||||||
|
@ -54,7 +51,6 @@ def test_on_attestation(spec, state):
|
||||||
next_slot(spec, state)
|
next_slot(spec, state)
|
||||||
|
|
||||||
attestation = get_valid_attestation(spec, state, slot=1)
|
attestation = get_valid_attestation(spec, state, slot=1)
|
||||||
yield 'attestation', attestation
|
|
||||||
indexed_attestation = spec.convert_to_indexed(state, attestation)
|
indexed_attestation = spec.convert_to_indexed(state, attestation)
|
||||||
spec.on_attestation(store, attestation)
|
spec.on_attestation(store, attestation)
|
||||||
assert (
|
assert (
|
||||||
|
@ -64,5 +60,3 @@ def test_on_attestation(spec, state):
|
||||||
root=attestation.data.target_root,
|
root=attestation.data.target_root,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
yield 'post', state
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import copy
|
||||||
from types import GeneratorType
|
from types import GeneratorType
|
||||||
from typing import (
|
from typing import (
|
||||||
List,
|
List,
|
||||||
|
@ -151,6 +152,9 @@ class Container(object):
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.hash_tree_root())
|
return hash(self.hash_tree_root())
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fields_dict(cls):
|
def get_fields_dict(cls):
|
||||||
return dict(cls.__annotations__)
|
return dict(cls.__annotations__)
|
||||||
|
|
Loading…
Reference in New Issue