From c1101a81813c470c6768e000f0fd34f07bfecbe9 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 8 Apr 2021 14:29:05 +0600 Subject: [PATCH 1/4] Apply new terminology to the merge spec --- specs/merge/beacon-chain.md | 102 ++++++++++++++++++------------------ specs/merge/fork-choice.md | 2 +- specs/merge/validator.md | 24 ++++----- 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 86bb0bc957..a170e4ed0b 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -20,17 +20,17 @@ - [`BeaconBlockBody`](#beaconblockbody) - [`BeaconState`](#beaconstate) - [New containers](#new-containers) - - [`ApplicationPayload`](#applicationpayload) - - [`ApplicationBlockHeader`](#applicationblockheader) + - [`ExecutionPayload`](#executionpayload) + - [`ExecutionPayloadHeader`](#executionpayloadheader) - [Helper functions](#helper-functions) - [Misc](#misc) - [`is_transition_completed`](#is_transition_completed) - [`is_transition_block`](#is_transition_block) - [Block processing](#block-processing) - - [Application payload processing](#application-payload-processing) - - [`get_application_state`](#get_application_state) - - [`application_state_transition`](#application_state_transition) - - [`process_application_payload`](#process_application_payload) + - [Execution payload processing](#execution-payload-processing) + - [`get_execution_state`](#get_execution_state) + - [`execution_state_transition`](#execution_state_transition) + - [`process_execution_payload`](#process_execution_payload) @@ -38,7 +38,7 @@ ## Introduction This is a patch implementing the executable beacon chain proposal. -It enshrines application-layer execution and validity as a first class citizen at the core of the beacon chain. +It enshrines transaction execution and validity as a first class citizen at the core of the beacon chain. ## Custom types @@ -73,32 +73,32 @@ order and append any additional fields to the end. #### `BeaconBlockBody` -*Note*: `BeaconBlockBody` fields remain unchanged other than the addition of `application_payload`. +*Note*: `BeaconBlockBody` fields remain unchanged other than the addition of `execution_payload`. ```python class BeaconBlockBody(phase0.BeaconBlockBody): - application_payload: ApplicationPayload # [New in Merge] application payload + execution_payload: ExecutionPayload # [New in Merge] ``` #### `BeaconState` -*Note*: `BeaconState` fields remain unchanged other than addition of `latest_application_block_header`. +*Note*: `BeaconState` fields remain unchanged other than addition of `latest_execution_payload_header`. ```python class BeaconState(phase0.BeaconState): - # Application-layer - latest_application_block_header: ApplicationBlockHeader # [New in Merge] + # Execution-layer + latest_execution_payload_header: ExecutionPayloadHeader # [New in Merge] ``` ### New containers -#### `ApplicationPayload` +#### `ExecutionPayload` -The application payload included in a `BeaconBlockBody`. +The execution payload included in a `BeaconBlockBody`. ```python -class ApplicationPayload(Container): - block_hash: Bytes32 # Hash of application block +class ExecutionPayload(Container): + block_hash: Bytes32 # Hash of execution block parent_hash: Bytes32 coinbase: Bytes20 state_root: Bytes32 @@ -110,15 +110,15 @@ class ApplicationPayload(Container): transactions: List[OpaqueTransaction, MAX_APPLICATION_TRANSACTIONS] ``` -#### `ApplicationBlockHeader` +#### `ExecutionPayloadHeader` -The application block header included in a `BeaconState`. +The execution payload header included in a `BeaconState`. -*Note:* Holds application payload data without transaction list. +*Note:* Holds execution payload data without transaction bodies. ```python -class ApplicationBlockHeader(Container): - block_hash: Bytes32 # Hash of application block +class ExecutionPayloadHeader(Container): + block_hash: Bytes32 # Hash of execution block parent_hash: Bytes32 coinbase: Bytes20 state_root: Bytes32 @@ -138,14 +138,14 @@ class ApplicationBlockHeader(Container): ```python def is_transition_completed(state: BeaconState) -> boolean: - return state.latest_application_block_header.block_hash != Bytes32() + return state.latest_execution_payload_header.block_hash != Bytes32() ``` #### `is_transition_block` ```python def is_transition_block(state: BeaconState, block_body: BeaconBlockBody) -> boolean: - return state.latest_application_block_header.block_hash == Bytes32() and block_body.application_payload.block_hash != Bytes32() + return state.latest_execution_payload_header.block_hash == Bytes32() and block_body.execution_payload.block_hash != Bytes32() ``` ### Block processing @@ -156,54 +156,54 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) - process_application_payload(state, block.body) # [New in Merge] + process_execution_payload(state, block.body) # [New in Merge] ``` -#### Application payload processing +#### Execution payload processing -##### `get_application_state` +##### `get_execution_state` -*Note*: `ApplicationState` class is an abstract class representing ethereum application state. +*Note*: `ExecutionState` class is an abstract class representing ethereum execution state. -Let `get_application_state(application_state_root: Bytes32) -> ApplicationState` be the function that given the root hash returns a copy of ethereum application state. +Let `get_execution_state(execution_state_root: Bytes32) -> ExecutionState` be the function that given the root hash returns a copy of ethereum execution state. The body of the function is implementation dependent. -##### `application_state_transition` +##### `execution_state_transition` -Let `application_state_transition(application_state: ApplicationState, application_payload: ApplicationPayload) -> None` be the transition function of ethereum application state. +Let `execution_state_transition(execution_state: ExecutionState, execution_payload: ExecutionPayload) -> None` be the transition function of ethereum execution state. The body of the function is implementation dependent. -*Note*: `application_state_transition` must throw `AssertionError` if either the transition itself or one of the post-transition verifications has failed. +*Note*: `execution_state_transition` must throw `AssertionError` if either the transition itself or one of the pre or post conditions has failed. -##### `process_application_payload` +##### `process_execution_payload` ```python -def process_application_payload(state: BeaconState, body: BeaconBlockBody) -> None: +def process_execution_payload(state: BeaconState, body: BeaconBlockBody) -> None: """ Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions """ if not is_transition_completed(state): - assert body.application_payload == ApplicationPayload() + assert body.execution_payload == ExecutionPayload() return if not is_transition_block(state, body): - assert body.application_payload.parent_hash == state.latest_application_block_header.block_hash - assert body.application_payload.number == state.latest_application_block_header.number + 1 - - application_state = get_application_state(state.latest_application_block_header.state_root) - application_state_transition(application_state, body.application_payload) - - state.latest_application_block_header = ApplicationBlockHeader( - block_hash=application_payload.block_hash, - parent_hash=application_payload.parent_hash, - coinbase=application_payload.coinbase, - state_root=application_payload.state_root, - number=application_payload.number, - gas_limit=application_payload.gas_limit, - gas_used=application_payload.gas_used, - receipt_root=application_payload.receipt_root, - logs_bloom=application_payload.logs_bloom, - transactions_root=hash_tree_root(application_payload.transactions), + assert body.execution_payload.parent_hash == state.latest_execution_payload_header.block_hash + assert body.execution_payload.number == state.latest_execution_payload_header.number + 1 + + execution_state = get_execution_state(state.latest_execution_payload_header.state_root) + execution_state_transition(execution_state, body.execution_payload) + + state.latest_execution_payload_header = ExecutionPayloadHeader( + block_hash=execution_payload.block_hash, + parent_hash=execution_payload.parent_hash, + coinbase=execution_payload.coinbase, + state_root=execution_payload.state_root, + number=execution_payload.number, + gas_limit=execution_payload.gas_limit, + gas_used=execution_payload.gas_used, + receipt_root=execution_payload.receipt_root, + logs_bloom=execution_payload.logs_bloom, + transactions_root=hash_tree_root(execution_payload.transactions), ) ``` diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 8425358bf9..647a663c27 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -77,7 +77,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # [New in Merge] if is_transition_block(pre_state, block.body): # Delay consideration of block until PoW block is processed by the PoW node - pow_block = get_pow_block(block.body.application_payload.parent_hash) + pow_block = get_pow_block(block.body.execution_payload.parent_hash) assert pow_block.is_processed assert is_valid_transition_block(pow_block) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 1c43c9dd6a..5b26a21dd5 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -15,9 +15,9 @@ - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [Application Payload](#application-payload) + - [Execution Payload](#execution-payload) - [`get_pow_chain_head`](#get_pow_chain_head) - - [`produce_application_payload`](#produce_application_payload) + - [`produce_execution_payload`](#produce_execution_payload) @@ -34,37 +34,37 @@ All terminology, constants, functions, and protocol mechanics defined in the upd ## Beacon chain responsibilities -All validator responsibilities remain unchanged other than those noted below. Namely, the transition block handling and the addition of `ApplicationPayload`. +All validator responsibilities remain unchanged other than those noted below. Namely, the transition block handling and the addition of `ExecutionPayload`. ### Block proposal #### Constructing the `BeaconBlockBody` -##### Application Payload +##### Execution Payload ###### `get_pow_chain_head` Let `get_pow_chain_head() -> PowBlock` be the function that returns the head of the PoW chain. The body of the function is implementation specific. -###### `produce_application_payload` +###### `produce_execution_payload` -Let `produce_application_payload(parent_hash: Bytes32) -> ApplicationPayload` be the function that produces new instance of application payload. +Let `produce_execution_payload(parent_hash: Bytes32) -> ExecutionPayload` be the function that produces new instance of execution payload. The body of this function is implementation dependent. -* Set `block.body.application_payload = get_application_payload(state)` where: +* Set `block.body.execution_payload = get_execution_payload(state)` where: ```python -def get_application_payload(state: BeaconState) -> ApplicationPayload: +def get_execution_payload(state: BeaconState) -> ExecutionPayload: if not is_transition_completed(state): pow_block = get_pow_chain_head() if not is_valid_transition_block(pow_block): # Pre-merge, empty payload - return ApplicationPayload() + return ExecutionPayload() else: # Signify merge via producing on top of the last PoW block - return produce_application_payload(pow_block.block_hash) + return produce_execution_payload(pow_block.block_hash) # Post-merge, normal payload - application_parent_hash = state.latest_application_block_header.block_hash - return produce_application_payload(application_parent_hash) + execution_parent_hash = state.latest_execution_payload_header.block_hash + return produce_execution_payload(execution_parent_hash) ``` From 13586cd9f88b1e58573eebf0028cd3c54991f667 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 8 Apr 2021 20:14:01 +0600 Subject: [PATCH 2/4] Polishing and fixes according to github comments --- specs/merge/beacon-chain.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a170e4ed0b..4e05c04ec8 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -138,14 +138,14 @@ class ExecutionPayloadHeader(Container): ```python def is_transition_completed(state: BeaconState) -> boolean: - return state.latest_execution_payload_header.block_hash != Bytes32() + return state.latest_execution_payload_header != ExecutionPayloadHeader() ``` #### `is_transition_block` ```python def is_transition_block(state: BeaconState, block_body: BeaconBlockBody) -> boolean: - return state.latest_execution_payload_header.block_hash == Bytes32() and block_body.execution_payload.block_hash != Bytes32() + return not is_transition_completed(state) and block_body.execution_payload != ExecutionPayload() ``` ### Block processing @@ -163,14 +163,14 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: ##### `get_execution_state` -*Note*: `ExecutionState` class is an abstract class representing ethereum execution state. +*Note*: `ExecutionState` class is an abstract class representing Ethereum execution state. -Let `get_execution_state(execution_state_root: Bytes32) -> ExecutionState` be the function that given the root hash returns a copy of ethereum execution state. +Let `get_execution_state(execution_state_root: Bytes32) -> ExecutionState` be the function that given the root hash returns a copy of Ethereum execution state. The body of the function is implementation dependent. ##### `execution_state_transition` -Let `execution_state_transition(execution_state: ExecutionState, execution_payload: ExecutionPayload) -> None` be the transition function of ethereum execution state. +Let `execution_state_transition(execution_state: ExecutionState, execution_payload: ExecutionPayload) -> None` be the transition function of Ethereum execution state. The body of the function is implementation dependent. *Note*: `execution_state_transition` must throw `AssertionError` if either the transition itself or one of the pre or post conditions has failed. @@ -183,16 +183,18 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody) -> None Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions """ + execution_payload = body.execution_payload + if not is_transition_completed(state): - assert body.execution_payload == ExecutionPayload() + assert execution_payload == ExecutionPayload() return if not is_transition_block(state, body): - assert body.execution_payload.parent_hash == state.latest_execution_payload_header.block_hash - assert body.execution_payload.number == state.latest_execution_payload_header.number + 1 + assert execution_payload.parent_hash == state.latest_execution_payload_header.block_hash + assert execution_payload.number == state.latest_execution_payload_header.number + 1 execution_state = get_execution_state(state.latest_execution_payload_header.state_root) - execution_state_transition(execution_state, body.execution_payload) + execution_state_transition(execution_state, execution_payload) state.latest_execution_payload_header = ExecutionPayloadHeader( block_hash=execution_payload.block_hash, From 68b11ad4ad1c175e8f5e682707734427f18ff8fd Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 8 Apr 2021 20:14:34 +0600 Subject: [PATCH 3/4] Fix pre-condition checks in process_execution_payload --- specs/merge/beacon-chain.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 4e05c04ec8..26ce63a08f 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -185,11 +185,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody) -> None execution_payload = body.execution_payload - if not is_transition_completed(state): - assert execution_payload == ExecutionPayload() - return - - if not is_transition_block(state, body): + if is_transition_completed(state): assert execution_payload.parent_hash == state.latest_execution_payload_header.block_hash assert execution_payload.number == state.latest_execution_payload_header.number + 1 From ffe7d6db6a4d15a355ef9b5d6072d440c2786fac Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 9 Apr 2021 15:36:45 +0600 Subject: [PATCH 4/4] Add pre-merge path to the process_execution_payload --- specs/merge/beacon-chain.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 26ce63a08f..fbdab682ec 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -183,6 +183,10 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody) -> None Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions """ + # Pre-merge, skip processing + if not is_transition_completed(state) and not is_transition_block(state, body): + return + execution_payload = body.execution_payload if is_transition_completed(state):