diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index e08ea09b6..9e38fd548 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -69,7 +69,7 @@ class Store(object): genesis_time: uint64 justified_checkpoint: Checkpoint finalized_checkpoint: Checkpoint - queued_justified_checkpoints: List[Checkpoint, 2**40] = field(default_factory=list) + best_justified_checkpoint: Checkpoint blocks: Dict[Hash, BeaconBlock] = field(default_factory=dict) block_states: Dict[Hash, BeaconState] = field(default_factory=dict) checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) @@ -89,6 +89,7 @@ def get_genesis_store(genesis_state: BeaconState) -> Store: genesis_time=genesis_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()}, @@ -147,14 +148,17 @@ def get_head(store: Store) -> Hash: #### `should_update_justified_checkpoint` ```python -def should_update_justified_checkpoint(store: Store, justified_checkpoint: Checkpoint) -> bool: +def should_update_justified_checkpoint(store: Store, new_justified_checkpoint: Checkpoint) -> bool: if get_current_slot(store) % SLOTS_PER_EPOCH < SAFE_SLOTS_TO_UPDATE_JUSTIFIED: return True - justified_block = store.blocks[justified_checkpoint.root] - if justified_block.slot <= compute_start_slot_at_epoch(store.justified_checkpoint.epoch): + new_justified_block = store.blocks[new_justified_checkpoint.root] + if new_justified_block.slot <= compute_start_slot_at_epoch(store.justified_checkpoint.epoch): return False - if not get_ancestor(store, justified_checkpoint.root, store.blocks[justified_checkpoint.root].slot): + if not ( + get_ancestor(store, new_justified_checkpoint.root, store.blocks[store.justified_checkpoint.root].slot) == + store.justified_checkpoint.root + ): return False return True @@ -175,12 +179,9 @@ def on_tick(store: Store, time: uint64) -> None: # Not a new epoch, return if not (current_slot > previous_slot and current_slot % SLOTS_PER_EPOCH == 0): return - # If new epoch and there are queued_justified_checkpoints, update if any is better than the best in store - if any(store.queued_justified_checkpoints): - best_justified_checkpoint = max(store.queued_justified_checkpoints, key=lambda checkpoint: checkpoint.epoch) - if best_justified_checkpoint.epoch > store.justified_checkpoint.epoch: - store.justified_checkpoint = best_justified_checkpoint - store.queued_justified_checkpoints = [] + # Update store.justified_checkpoint if a better checkpoint is know + if store.best_justified_checkpoint.epoch > store.justified_checkpoint.epoch: + store.justified_checkpoint = store.best_justified_checkpoint ``` #### `on_block` @@ -208,10 +209,9 @@ def on_block(store: Store, block: BeaconBlock) -> None: # Update justified checkpoint if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch: + store.best_justified_checkpoint = state.current_justified_checkpoint if should_update_justified_checkpoint(store, state.current_justified_checkpoint): store.justified_checkpoint = state.current_justified_checkpoint - else: - store.queued_justified_checkpoints.append(state.current_justified_checkpoint) # Update finalized checkpoint if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch: diff --git a/test_libs/pyspec/eth2spec/test/fork_choice/test_on_block.py b/test_libs/pyspec/eth2spec/test/fork_choice/test_on_block.py index 36e61f0b5..e42cb1ac4 100644 --- a/test_libs/pyspec/eth2spec/test/fork_choice/test_on_block.py +++ b/test_libs/pyspec/eth2spec/test/fork_choice/test_on_block.py @@ -202,4 +202,4 @@ def test_on_block_outside_safe_slots_and_old_block(spec, state): run_on_block(spec, store, block) assert store.justified_checkpoint != new_justified - assert store.queued_justified_checkpoints[0] == new_justified + assert store.best_justified_checkpoint == new_justified diff --git a/test_libs/pyspec/eth2spec/test/fork_choice/test_on_tick.py b/test_libs/pyspec/eth2spec/test/fork_choice/test_on_tick.py index 2ba89ebca..77222f65c 100644 --- a/test_libs/pyspec/eth2spec/test/fork_choice/test_on_tick.py +++ b/test_libs/pyspec/eth2spec/test/fork_choice/test_on_tick.py @@ -1,7 +1,7 @@ from eth2spec.test.context import with_all_phases, spec_state_test -def run_on_tick(spec, store, time, new_justified_checkpoint=None): +def run_on_tick(spec, store, time, new_justified_checkpoint=False): previous_justified_checkpoint = store.justified_checkpoint spec.on_tick(store, time) @@ -9,8 +9,9 @@ def run_on_tick(spec, store, time, new_justified_checkpoint=None): assert store.time == time if new_justified_checkpoint: - assert store.justified_checkpoint == new_justified_checkpoint + assert store.justified_checkpoint == store.best_justified_checkpoint assert store.justified_checkpoint.epoch > previous_justified_checkpoint.epoch + assert store.justified_checkpoint.root != previous_justified_checkpoint.root else: assert store.justified_checkpoint == previous_justified_checkpoint @@ -28,30 +29,12 @@ def test_update_justified_single(spec, state): store = spec.get_genesis_store(state) seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - new_justified = spec.Checkpoint( + store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, root=b'\x55' * 32, ) - store.queued_justified_checkpoints.append(new_justified) - run_on_tick(spec, store, store.time + seconds_per_epoch, new_justified) - - -@with_all_phases -@spec_state_test -def test_update_justified_multiple(spec, state): - store = spec.get_genesis_store(state) - seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - - new_justified = None # remember checkpoint with latest epoch - for i in range(3): - new_justified = spec.Checkpoint( - epoch=store.justified_checkpoint.epoch + i + 1, - root=i.to_bytes(1, byteorder='big') * 32, - ) - store.queued_justified_checkpoints.append(new_justified) - - run_on_tick(spec, store, store.time + seconds_per_epoch, new_justified) + run_on_tick(spec, store, store.time + seconds_per_epoch, True) @with_all_phases @@ -60,11 +43,10 @@ def test_no_update_same_slot_at_epoch_boundary(spec, state): store = spec.get_genesis_store(state) seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - new_justified = spec.Checkpoint( + store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, root=b'\x55' * 32, ) - store.queued_justified_checkpoints.append(new_justified) # set store time to already be at epoch boundary store.time = seconds_per_epoch @@ -77,11 +59,10 @@ def test_no_update_same_slot_at_epoch_boundary(spec, state): def test_no_update_not_epoch_boundary(spec, state): store = spec.get_genesis_store(state) - new_justified = spec.Checkpoint( + store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, root=b'\x55' * 32, ) - store.queued_justified_checkpoints.append(new_justified) run_on_tick(spec, store, store.time + spec.SECONDS_PER_SLOT) @@ -92,14 +73,13 @@ def test_no_update_new_justified_equal_epoch(spec, state): store = spec.get_genesis_store(state) seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - new_justified = spec.Checkpoint( + store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, root=b'\x55' * 32, ) - store.queued_justified_checkpoints.append(new_justified) store.justified_checkpoint = spec.Checkpoint( - epoch=new_justified.epoch, + epoch=store.best_justified_checkpoint.epoch, root=b'\44' * 32, ) @@ -112,14 +92,13 @@ def test_no_update_new_justified_later_epoch(spec, state): store = spec.get_genesis_store(state) seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH - new_justified = spec.Checkpoint( + store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, root=b'\x55' * 32, ) - store.queued_justified_checkpoints.append(new_justified) store.justified_checkpoint = spec.Checkpoint( - epoch=new_justified.epoch + 1, + epoch=store.best_justified_checkpoint.epoch + 1, root=b'\44' * 32, )