Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add terminal block hash override #2617

Merged
merged 10 commits into from
Sep 27, 2021
2 changes: 2 additions & 0 deletions configs/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions configs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions specs/merge/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 7 additions & 0 deletions specs/merge/client-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand All @@ -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.
7 changes: 5 additions & 2 deletions specs/merge/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down
25 changes: 19 additions & 6 deletions specs/merge/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down