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) - [Helpers](#helpers)
- [`LatestMessage`](#latestmessage) - [`LatestMessage`](#latestmessage)
- [`Store`](#store) - [`Store`](#store)
- [`get_genesis_store`](#get_genesis_store) - [`get_forkchoice_store`](#get_forkchoice_store)
- [`get_slots_since_genesis`](#get_slots_since_genesis) - [`get_slots_since_genesis`](#get_slots_since_genesis)
- [`get_current_slot`](#get_current_slot) - [`get_current_slot`](#get_current_slot)
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start) - [`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 ## 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_tick(time)` whenever `time > store.time` where `time` is the current Unix time
- `on_block(block)` whenever a block `block: SignedBeaconBlock` is received - `on_block(block)` whenever a block `block: SignedBeaconBlock` is received
@ -79,29 +79,35 @@ class Store(object):
justified_checkpoint: Checkpoint justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint finalized_checkpoint: Checkpoint
best_justified_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) block_states: Dict[Root, BeaconState] = field(default_factory=dict)
checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict)
latest_messages: Dict[ValidatorIndex, LatestMessage] = 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 ```python
def get_genesis_store(genesis_state: BeaconState) -> Store: def get_forkchoice_store(anchor_state: BeaconState) -> Store:
genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state)) anchor_block_header = anchor_state.latest_block_header.copy()
root = hash_tree_root(genesis_block) if anchor_block_header.state_root == Bytes32():
justified_checkpoint = Checkpoint(epoch=GENESIS_EPOCH, root=root) anchor_block_header.state_root = hash_tree_root(anchor_state)
finalized_checkpoint = Checkpoint(epoch=GENESIS_EPOCH, root=root) 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( return Store(
time=genesis_state.genesis_time, time=anchor_state.genesis_time,
genesis_time=genesis_state.genesis_time, genesis_time=anchor_state.genesis_time,
justified_checkpoint=justified_checkpoint, justified_checkpoint=justified_checkpoint,
finalized_checkpoint=finalized_checkpoint, finalized_checkpoint=finalized_checkpoint,
best_justified_checkpoint=justified_checkpoint, best_justified_checkpoint=justified_checkpoint,
blocks={root: genesis_block}, blocks={anchor_root: anchor_block_header},
block_states={root: genesis_state.copy()}, block_states={anchor_root: anchor_state.copy()},
checkpoint_states={justified_checkpoint: genesis_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 @spec_state_test
def test_genesis(spec, state): def test_genesis(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root()) genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block) assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
@ -43,7 +43,7 @@ def test_genesis(spec, state):
@spec_state_test @spec_state_test
def test_chain_no_attestations(spec, state): def test_chain_no_attestations(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root()) genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block) 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() genesis_state = state.copy()
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root()) genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block) 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() genesis_state = state.copy()
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root()) genesis_block = spec.BeaconBlock(state_root=state.hash_tree_root())
assert spec.get_head(store) == spec.hash_tree_root(genesis_block) 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): def test_filtered_block_tree(spec, state):
# Initialization # Initialization
genesis_state_root = state.hash_tree_root() 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) genesis_block = spec.BeaconBlock(state_root=genesis_state_root)
# transition state past initial couple of epochs # 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 @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_current_epoch(spec, state): 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) spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * 2)
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
@ -46,7 +46,7 @@ def test_on_attestation_current_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_previous_epoch(spec, state): 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) spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
@ -65,7 +65,7 @@ def test_on_attestation_previous_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_past_epoch(spec, state): 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 # move time forward 2 epochs
time = store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH 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 @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_mismatched_target_and_slot(spec, state): 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) spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state) 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 @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_target_not_in_store(spec, state): 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 time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time) spec.on_tick(store, time)
@ -131,7 +131,7 @@ def test_on_attestation_target_not_in_store(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_beacon_block_not_in_store(spec, state): 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 time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time) spec.on_tick(store, time)
@ -159,7 +159,7 @@ def test_on_attestation_beacon_block_not_in_store(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_future_epoch(spec, state): 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 time = 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time) spec.on_tick(store, time)
@ -179,7 +179,7 @@ def test_on_attestation_future_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_future_block(spec, state): 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 time = spec.SECONDS_PER_SLOT * 5
spec.on_tick(store, time) spec.on_tick(store, time)
@ -199,7 +199,7 @@ def test_on_attestation_future_block(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_same_slot(spec, state): 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 time = 1 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time) spec.on_tick(store, time)
@ -215,7 +215,7 @@ def test_on_attestation_same_slot(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_on_attestation_invalid_attestation(spec, state): 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 time = 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time) spec.on_tick(store, time)

View File

@ -36,7 +36,7 @@ def apply_next_epoch_with_attestations(spec, state, store):
@spec_state_test @spec_state_test
def test_basic(spec, state): def test_basic(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) spec.on_tick(store, time)
assert store.time == time assert store.time == time
@ -60,7 +60,7 @@ def test_basic(spec, state):
@spec_state_test @spec_state_test
def test_on_block_checkpoints(spec, state): def test_on_block_checkpoints(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) spec.on_tick(store, time)
@ -86,7 +86,7 @@ def test_on_block_checkpoints(spec, state):
@spec_state_test @spec_state_test
def test_on_block_future_block(spec, state): def test_on_block_future_block(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
# do not tick time # do not tick time
@ -100,7 +100,7 @@ def test_on_block_future_block(spec, state):
@spec_state_test @spec_state_test
def test_on_block_bad_parent_root(spec, state): def test_on_block_bad_parent_root(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) spec.on_tick(store, time)
@ -120,7 +120,7 @@ def test_on_block_bad_parent_root(spec, state):
@spec_state_test @spec_state_test
def test_on_block_before_finalized(spec, state): def test_on_block_before_finalized(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) spec.on_tick(store, time)
@ -139,7 +139,7 @@ def test_on_block_before_finalized(spec, state):
@spec_state_test @spec_state_test
def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state): def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) spec.on_tick(store, time)
@ -170,7 +170,7 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
@spec_state_test @spec_state_test
def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state): def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
# Initialization # Initialization
store = spec.get_genesis_store(state) store = spec.get_forkchoice_store(state)
time = 100 time = 100
spec.on_tick(store, time) 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 @with_all_phases
@spec_state_test @spec_state_test
def test_basic(spec, state): 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) run_on_tick(spec, store, store.time + 1)
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_update_justified_single(spec, state): 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 seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint( store.best_justified_checkpoint = spec.Checkpoint(
@ -40,7 +40,7 @@ def test_update_justified_single(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_no_update_same_slot_at_epoch_boundary(spec, state): 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 seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint( store.best_justified_checkpoint = spec.Checkpoint(
@ -57,7 +57,7 @@ def test_no_update_same_slot_at_epoch_boundary(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_no_update_not_epoch_boundary(spec, state): 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( store.best_justified_checkpoint = spec.Checkpoint(
epoch=store.justified_checkpoint.epoch + 1, epoch=store.justified_checkpoint.epoch + 1,
@ -70,7 +70,7 @@ def test_no_update_not_epoch_boundary(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_no_update_new_justified_equal_epoch(spec, state): 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 seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint( store.best_justified_checkpoint = spec.Checkpoint(
@ -89,7 +89,7 @@ def test_no_update_new_justified_equal_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_no_update_new_justified_later_epoch(spec, state): 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 seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint( store.best_justified_checkpoint = spec.Checkpoint(