diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index 099843067..86afdb7d5 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -136,17 +136,62 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei: )) ``` +#### `filter_block_tree` + +```python +def filter_block_tree(store, block_root, blocks): + block = store.blocks[block_root] + children = [ + root for root in store.blocks.keys() + if store.blocks[root].parent_root == block + ] + + # If any children branches contain expected finalized/justified checkpoints, + # add to filtered block-tree and signal viability to parent. + if any(children): + if True in [filter_block_tree(child, blocks) for child in children]: + blocks[block_root] = block + return True + return False + + # If leaf block, check finalized/justified checkpoints as matching latest. + # If matching, add to viable block-tree and signal viability to parent. + head_state = store.block_states[block_root] + is_viable_branch = ( + head_state.finalized_checkpoint == store.finalized_checkpoint + and head_state.current_justified_checkpoint == store.justified_checkpoint + ) + if is_viable_branch: + blocks[block_root] = block + return True + + # Otherwise, not viable + return False +``` + +#### `get_filtered_block_tree` + +```python +def get_filtered_block_tree(store: Store) -> Dict[Root, BeaconBlock]: + head = store.justified_checkpoint.root + blocks = {} + filter_block_tree(head, blocks) + return blocks +``` + #### `get_head` ```python def get_head(store: Store) -> Root: + # Get filtered block tree that includes viable branches + blocks = get_filtered_block_tree(store) # Execute the LMD-GHOST fork choice head = store.justified_checkpoint.root justified_slot = compute_start_slot_at_epoch(store.justified_checkpoint.epoch) while True: children = [ - root for root in store.blocks.keys() - if store.blocks[root].parent_root == head and store.blocks[root].slot > justified_slot + root for root in blocks.keys() + if blocks[root].parent_root == head and blocks[root].slot > justified_slot ] if len(children) == 0: return head