From f58ba8f5b200d158c0323e5b986456252bacbe6e Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 10 May 2021 15:48:37 +0200 Subject: [PATCH] define execution engine protocol --- specs/merge/beacon-chain.md | 39 +++++++++++++++++++++------- specs/merge/fork-choice.md | 52 ++++++++++++++++++++++++++++++++++--- specs/merge/validator.md | 28 +++++++++++++++++--- 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 626a86724..bca58eb7f 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -22,6 +22,9 @@ - [New containers](#new-containers) - [`ExecutionPayload`](#executionpayload) - [`ExecutionPayloadHeader`](#executionpayloadheader) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [`new_block`](#new_block) - [Helper functions](#helper-functions) - [Misc](#misc) - [`is_execution_enabled`](#is_execution_enabled) @@ -30,7 +33,6 @@ - [`compute_time_at_slot`](#compute_time_at_slot) - [Block processing](#block-processing) - [Execution payload processing](#execution-payload-processing) - - [`verify_execution_state_transition`](#verify_execution_state_transition) - [`process_execution_payload`](#process_execution_payload) @@ -137,6 +139,30 @@ class ExecutionPayloadHeader(Container): transactions_root: Root ``` +## Protocols + +### `ExecutionEngine` + +The `ExecutionEngine` protocol separates the consensus and execution sub-systems. +The consensus implementation references an instance of this sub-system with `EXECUTION_ENGINE`. + +The following methods are added to the `ExecutionEngine` protocol for use in the state transition: + +#### `new_block` + +Verifies the given `ExecutionPayload` with respect to execution state transition, and persists changes if valid. + +The body of this function is implementation dependent. +The Consensus API may be used to implement this with an external execution engine. + +```python +def new_block(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: + """ + Returns True if the ``execution_payload`` was verified and processed successfully, False otherwise. + """ + ... +``` + ## Helper functions ### Misc @@ -182,20 +208,15 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_operations(state, block.body) # Pre-merge, skip execution payload processing if is_execution_enabled(state, block): - process_execution_payload(state, block.body.execution_payload) # [New in Merge] + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Merge] ``` #### Execution payload processing -##### `verify_execution_state_transition` - -Let `verify_execution_state_transition(execution_payload: ExecutionPayload) -> bool` be the function that verifies given `ExecutionPayload` with respect to execution state transition. -The body of the function is implementation dependent. - ##### `process_execution_payload` ```python -def process_execution_payload(state: BeaconState, execution_payload: ExecutionPayload) -> None: +def process_execution_payload(state: BeaconState, execution_payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: """ Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions """ @@ -205,7 +226,7 @@ def process_execution_payload(state: BeaconState, execution_payload: ExecutionPa assert execution_payload.timestamp == compute_time_at_slot(state, state.slot) - assert verify_execution_state_transition(execution_payload) + assert execution_engine.new_block(execution_payload) state.latest_execution_payload_header = ExecutionPayloadHeader( block_hash=execution_payload.block_hash, diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index f478dd7e6..9e6c341bc 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -8,11 +8,16 @@ - [Introduction](#introduction) - - [Helpers](#helpers) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [`set_head`](#set_head) + - [`finalize_block`](#finalize_block) +- [Containers](#containers) - [`PowBlock`](#powblock) +- [Helper functions](#helper-functions) - [`get_pow_block`](#get_pow_block) - [`is_valid_transition_block`](#is_valid_transition_block) - - [Updated fork-choice handlers](#updated-fork-choice-handlers) +- [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -24,7 +29,44 @@ This is the modification of the fork choice according to the executable beacon c *Note*: It introduces the process of transition from the last PoW block to the first PoS block. -### Helpers +## Protocols + +### `ExecutionEngine` + +The following methods are added to the `ExecutionEngine` protocol for use in the fork choice: + +#### `set_head` + +Re-organizes the execution payload chain and corresponding state to make `block_hash` the head. + +The body of this function is implementation dependent. +The Consensus API may be used to implement this with an external execution engine. + +```python +def set_head(self: ExecutionEngine, block_hash: Hash32) -> bool: + """ + Returns True if the ``block_hash`` was successfully set as head of the execution payload chain. + """ + ... +``` + +#### `finalize_block` + +Applies finality to the execution state: it irreversibly persists the chain of all execution payloads +and corresponding state, up to and including `block_hash`. + +The body of this function is implementation dependent. +The Consensus API may be used to implement this with an external execution engine. + +```python +def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool: + """ + Returns True if the data up to and including ``block_hash`` was successfully finalized. + """ + ... +``` + +## Containers #### `PowBlock` @@ -36,6 +78,8 @@ class PowBlock(Container): total_difficulty: uint256 ``` +## Helper functions + #### `get_pow_block` Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given the hash of the PoW block returns its data. @@ -52,7 +96,7 @@ def is_valid_transition_block(block: PowBlock) -> bool: return block.is_valid and is_total_difficulty_reached ``` -### Updated fork-choice handlers +## Updated fork-choice handlers #### `on_block` diff --git a/specs/merge/validator.md b/specs/merge/validator.md index dccc5727b..21fc49a36 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -12,6 +12,9 @@ - [Introduction](#introduction) - [Prerequisites](#prerequisites) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [`assemble_block`](#assemble_block) - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) @@ -32,6 +35,25 @@ This document is an extension of the [Phase 0 -- Validator](../phase0/validator. All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [The Merge](./beacon-chain.md) are requisite for this document and used throughout. Please see related Beacon Chain doc before continuing and use them as a reference throughout. +## Protocols + +### `ExecutionEngine` + +The following methods are added to the `ExecutionEngine` protocol for use as a validator: + +#### `assemble_block` + +Produces a new instance of an execution payload, with the specified timestamp, +on top of the execution payload chain tip identified by `block_head`. + +The body of this function is implementation dependent. +The Consensus API may be used to implement this with an external execution engine. + +```python +def assemble_block(self: ExecutionEngine, block_hash: Hash32, timestamp: uint64) -> ExecutionPayload: + ... +``` + ## Beacon chain responsibilities All validator responsibilities remain unchanged other than those noted below. Namely, the transition block handling and the addition of `ExecutionPayload`. @@ -49,12 +71,12 @@ Let `get_pow_chain_head() -> PowBlock` be the function that returns the head of ###### `produce_execution_payload` Let `produce_execution_payload(parent_hash: Hash32, timestamp: uint64) -> ExecutionPayload` be the function that produces new instance of execution payload. -The body of this function is implementation dependent. +The `ExecutionEngine` protocol is used for the implementation specific part of execution payload proposals. * Set `block.body.execution_payload = get_execution_payload(state)` where: ```python -def get_execution_payload(state: BeaconState) -> ExecutionPayload: +def get_execution_payload(state: BeaconState, execution_engine: ExecutionEngine) -> ExecutionPayload: if not is_transition_completed(state): pow_block = get_pow_chain_head() if not is_valid_transition_block(pow_block): @@ -63,7 +85,7 @@ def get_execution_payload(state: BeaconState) -> ExecutionPayload: else: # Signify merge via producing on top of the last PoW block timestamp = compute_time_at_slot(state, state.slot) - return produce_execution_payload(pow_block.block_hash, timestamp) + return execution_engine.assemble_block(pow_block.block_hash, timestamp) # Post-merge, normal payload execution_parent_hash = state.latest_execution_payload_header.block_hash