diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 58b664d0c..77d7a136f 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -7,6 +7,8 @@ PRESET_BASE: 'mainnet' # --------------------------------------------------------------- # TBD, 2**256-2**10 is a placeholder TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912 +# By default, don't use this param +TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 # Genesis diff --git a/configs/minimal.yaml b/configs/minimal.yaml index d164dc2e2..a8b30fd54 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -7,6 +7,8 @@ PRESET_BASE: 'minimal' # --------------------------------------------------------------- # TBD, 2**256-2**10 is a placeholder TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912 +# By default, don't use this param +TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 # Genesis diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 053c829f1..56476cedd 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -85,6 +85,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | Name | Value | | - | - | | `TERMINAL_TOTAL_DIFFICULTY` | **TBD** | +| `TERMINAL_BLOCK_HASH` | `Hash32('0x0000000000000000000000000000000000000000000000000000000000000000')` | ## Containers diff --git a/specs/merge/client-settings.md b/specs/merge/client-settings.md index 64b2b20e6..287e557db 100644 --- a/specs/merge/client-settings.md +++ b/specs/merge/client-settings.md @@ -4,6 +4,7 @@ - [The Merge -- Client Settings](#the-merge----client-settings) - [Override terminal total difficulty](#override-terminal-total-difficulty) + - [Override terminal block hash](#override-terminal-block-hash) @@ -19,3 +20,9 @@ To coordinate manual overrides to [`TERMINAL_TOTAL_DIFFICULTY`](./beacon-chain.m Except under exceptional scenarios, this setting is expected to not be used. Sufficient warning to the user about this exceptional configurable setting should be provided. +### Override terminal block hash + +To allow for transition coordination around a specific PoW block, clients must also provide `--terminal-block-hash-override` as a configurable setting. +The value provided by this setting takes precedence over the pre-configured `TERMINAL_BLOCK_HASH` parameter. + +Except under exceptional scenarios, this setting is expected to not be used. Sufficient warning to the user about this exceptional configurable setting should be provided. diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 1a333d678..ea4a5588a 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -74,6 +74,9 @@ Used by fork-choice handler, `on_block`. ```python def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool: + if block.block_hash == TERMINAL_BLOCK_HASH: + return True + is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY return is_total_difficulty_reached and is_parent_total_difficulty_valid @@ -100,7 +103,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: 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 - + # Check the block is valid and compute the post-state state = pre_state.copy() state_transition(state, signed_block, True) @@ -126,7 +129,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # 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 diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 1bc36b02d..2de4ef6b1 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -97,29 +97,42 @@ To obtain an execution payload, a block proposer building a block on top of a `s * `pow_chain` is a list that abstractly represents all blocks in the PoW chain * `fee_recipient` is the value suggested to be used for the `coinbase` field of the execution payload + ```python -def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequence[PowBlock]) -> Optional[PowBlock]: +def get_pow_block_at_terminal_total_difficulty(pow_chain: Sequence[PowBlock]) -> Optional[PowBlock]: # `pow_chain` abstractly represents all blocks in the PoW chain for block in pow_chain: parent = get_pow_block(block.parent_hash) - if block.total_difficulty >= total_difficulty and parent.total_difficulty < total_difficulty: + block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY + parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY + if block_reached_ttd and not parent_reached_ttd: return block return None +def get_terminal_pow_block(pow_chain: Sequence[PowBlock]) -> Optional[PowBlock]: + if TERMINAL_BLOCK_HASH != Hash32(): + # Terminal block hash override takes precedence over terminal total difficulty + pow_block_overrides = [block for block in pow_chain if block.block_hash == TERMINAL_BLOCK_HASH] + if not any(pow_block_overrides): + return None + return pow_block_overrides[0] + + return get_pow_block_at_terminal_total_difficulty(pow_chain) + + def prepare_execution_payload(state: BeaconState, pow_chain: Sequence[PowBlock], fee_recipient: ExecutionAddress, execution_engine: ExecutionEngine) -> Optional[PayloadId]: if not is_merge_complete(state): - terminal_pow_block = get_pow_block_at_total_difficulty(TERMINAL_TOTAL_DIFFICULTY, pow_chain) + terminal_pow_block = get_terminal_pow_block(pow_chain) if terminal_pow_block is None: # Pre-merge, no prepare payload call is needed return None - else: - # Signify merge via producing on top of the last PoW block - parent_hash = terminal_pow_block.block_hash + # Signify merge via producing on top of the terminal PoW block + parent_hash = terminal_pow_block.block_hash else: # Post-merge, normal payload parent_hash = state.latest_execution_payload_header.block_hash