4.5 KiB
4.5 KiB
Ethereum 2.0 The Merge
Notice: This document is a work-in-progress for researchers and implementers.
Table of contents
Introduction
This is the modification of the fork choice according to the executable beacon chain proposal.
Note: It introduces the process of transition from the last PoW block to the first PoS block.
Helpers
get_total_difficulty
Let get_total_difficulty(hash: Bytes32) -> uint256
be the function that returns the total difficulty of the PoW block specified by its hash.
Note: The function returns 0
if the block is either not yet processed or considered invalid. The latter two cases are considered indistinguishable to the current implementation of JSON-RPC.
is_valid_transition_block
Used by fork-choice handler, on_block
def is_valid_transition_block(block: BeaconBlock) -> boolean:
total_difficulty = get_total_difficulty(block.body.application_payload.block_hash)
return total_difficulty >= TRANSITION_TOTAL_DIFFICULTY
Updated fork-choice handlers
on_block
Note: The only modification is the addition of the verification of transition block conditions.
def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
block = signed_block.message
# Parent block must be known
assert block.parent_root in store.block_states
# Make a copy of the state to avoid mutability issues
pre_state = copy(store.block_states[block.parent_root])
# Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
assert get_current_slot(store) >= block.slot
# Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert block.slot > finalized_slot
# Check block is a descendant of the finalized block at the checkpoint finalized slot
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
# [Added in Merge] Consider delaying the beacon block processing until PoW block is accepted by the application node
if is_transition_block(pre_state, block.body):
assert is_valid_transition_block(block)
# Check the block is valid and compute the post-state
state = pre_state.copy()
state_transition(state, signed_block, True)
# Add new block to the store
store.blocks[hash_tree_root(block)] = block
# Add new state for this block to the store
store.block_states[hash_tree_root(block)] = state
# Update justified checkpoint
if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
if state.current_justified_checkpoint.epoch > store.best_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
# Update finalized checkpoint
if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
store.finalized_checkpoint = state.finalized_checkpoint
# Potentially update justified if different from store
if store.justified_checkpoint != state.current_justified_checkpoint:
# Update justified if new justified is later than store justified
if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
store.justified_checkpoint = state.current_justified_checkpoint
return
# Update justified if store justified is not in chain with finalized checkpoint
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
store.justified_checkpoint = state.current_justified_checkpoint