forkchoice store on top of any state now

This commit is contained in:
protolambda 2020-01-14 01:02:02 +01:00
parent 46be6aed1d
commit 6c74468142
No known key found for this signature in database
GPG Key ID: EC89FDBB2B4C7623
5 changed files with 48 additions and 42 deletions

View File

@ -14,7 +14,7 @@
- [Helpers](#helpers)
- [`LatestMessage`](#latestmessage)
- [`Store`](#store)
- [`get_genesis_store`](#get_genesis_store)
- [`get_forkchoice_store`](#get_forkchoice_store)
- [`get_slots_since_genesis`](#get_slots_since_genesis)
- [`get_current_slot`](#get_current_slot)
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start)
@ -38,7 +38,7 @@ This document is the beacon chain fork choice spec, part of Ethereum 2.0 Phase 0
## Fork choice
The head block root associated with a `store` is defined as `get_head(store)`. At genesis, let `store = get_genesis_store(genesis_state)` and update `store` by running:
The head block root associated with a `store` is defined as `get_head(store)`. At genesis, let `store = get_checkpoint_store(genesis_state)` and update `store` by running:
- `on_tick(time)` whenever `time > store.time` where `time` is the current Unix time
- `on_block(block)` whenever a block `block: SignedBeaconBlock` is received
@ -79,29 +79,35 @@ class Store(object):
justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
best_justified_checkpoint: Checkpoint
blocks: Dict[Root, BeaconBlock] = field(default_factory=dict)
blocks: Dict[Root, BeaconBlockHeader] = field(default_factory=dict)
block_states: Dict[Root, BeaconState] = field(default_factory=dict)
checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict)
latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict)
```
#### `get_genesis_store`
#### `get_forkchoice_store`
The provided anchor-state will be regarded as a trusted state, to not roll back beyond.
This should be the genesis state for a full client.
```python
def get_genesis_store(genesis_state: BeaconState) -> Store:
genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))
root = hash_tree_root(genesis_block)
justified_checkpoint = Checkpoint(epoch=GENESIS_EPOCH, root=root)
finalized_checkpoint = Checkpoint(epoch=GENESIS_EPOCH, root=root)
def get_forkchoice_store(anchor_state: BeaconState) -> Store:
anchor_block_header = anchor_state.latest_block_header.copy()
if anchor_block_header.state_root == Bytes32():
anchor_block_header.state_root = hash_tree_root(anchor_state)
anchor_root = hash_tree_root(anchor_block_header)
anchor_epoch = get_current_epoch(anchor_state)
justified_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
return Store(
time=genesis_state.genesis_time,
genesis_time=genesis_state.genesis_time,
time=anchor_state.genesis_time,
genesis_time=anchor_state.genesis_time,
justified_checkpoint=justified_checkpoint,
finalized_checkpoint=finalized_checkpoint,
best_justified_checkpoint=justified_checkpoint,
blocks={root: genesis_block},
block_states={root: genesis_state.copy()},
checkpoint_states={justified_checkpoint: genesis_state.copy()},
blocks={anchor_root: anchor_block_header},
block_states={anchor_root: anchor_state.copy()},
checkpoint_states={justified_checkpoint: anchor_state.copy()},
)
```

View File

@ -34,7 +34,7 @@ def add_attestation_to_store(spec, store, attestation):
@spec_state_test
def test_genesis(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
@ -43,7 +43,7 @@ def test_genesis(spec, state):
@spec_state_test
def test_chain_no_attestations(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
@ -66,7 +66,7 @@ def test_split_tie_breaker_no_attestations(spec, state):
genesis_state = state.copy()
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
@ -94,7 +94,7 @@ def test_shorter_chain_but_heavier_weight(spec, state):
genesis_state = state.copy()
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
@ -123,7 +123,7 @@ def test_shorter_chain_but_heavier_weight(spec, state):
def test_filtered_block_tree(spec, state):
# Initialization
genesis_state_root = state.hash_tree_root()
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=genesis_state_root)
# transition state past initial couple of epochs

View File

@ -27,7 +27,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
@with_all_phases
@spec_state_test
def test_on_attestation_current_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * 2)
block = build_empty_block_for_next_slot(spec, state)
@ -46,7 +46,7 @@ def test_on_attestation_current_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_previous_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state)
@ -65,7 +65,7 @@ def test_on_attestation_previous_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_past_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
# move time forward 2 epochs
time = store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
@ -87,7 +87,7 @@ def test_on_attestation_past_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_mismatched_target_and_slot(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state)
@ -110,7 +110,7 @@ def test_on_attestation_mismatched_target_and_slot(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_target_not_in_store(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time)
@ -131,7 +131,7 @@ def test_on_attestation_target_not_in_store(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_beacon_block_not_in_store(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time)
@ -159,7 +159,7 @@ def test_on_attestation_beacon_block_not_in_store(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_future_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
@ -179,7 +179,7 @@ def test_on_attestation_future_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_future_block(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * 5
spec.on_tick(store, time)
@ -199,7 +199,7 @@ def test_on_attestation_future_block(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_same_slot(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 1 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
@ -215,7 +215,7 @@ def test_on_attestation_same_slot(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_invalid_attestation(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)

View File

@ -36,7 +36,7 @@ def apply_next_epoch_with_attestations(spec, state, store):
@spec_state_test
def test_basic(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)
assert store.time == time
@ -60,7 +60,7 @@ def test_basic(spec, state):
@spec_state_test
def test_on_block_checkpoints(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)
@ -86,7 +86,7 @@ def test_on_block_checkpoints(spec, state):
@spec_state_test
def test_on_block_future_block(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
# do not tick time
@ -100,7 +100,7 @@ def test_on_block_future_block(spec, state):
@spec_state_test
def test_on_block_bad_parent_root(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)
@ -120,7 +120,7 @@ def test_on_block_bad_parent_root(spec, state):
@spec_state_test
def test_on_block_before_finalized(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)
@ -139,7 +139,7 @@ def test_on_block_before_finalized(spec, state):
@spec_state_test
def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)
@ -170,7 +170,7 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
@spec_state_test
def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
# Initialization
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
time = 100
spec.on_tick(store, time)

View File

@ -19,14 +19,14 @@ def run_on_tick(spec, store, time, new_justified_checkpoint=False):
@with_all_phases
@spec_state_test
def test_basic(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
run_on_tick(spec, store, store.time + 1)
@with_all_phases
@spec_state_test
def test_update_justified_single(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(
@ -40,7 +40,7 @@ def test_update_justified_single(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_same_slot_at_epoch_boundary(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(
@ -57,7 +57,7 @@ def test_no_update_same_slot_at_epoch_boundary(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_not_epoch_boundary(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
store.best_justified_checkpoint = spec.Checkpoint(
epoch=store.justified_checkpoint.epoch + 1,
@ -70,7 +70,7 @@ def test_no_update_not_epoch_boundary(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_new_justified_equal_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(
@ -89,7 +89,7 @@ def test_no_update_new_justified_equal_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_new_justified_later_epoch(spec, state):
store = spec.get_genesis_store(state)
store = spec.get_forkchoice_store(state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(