From 6ba1f22404181408259d363b7ed311208816d6f8 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 1 Sep 2021 18:42:58 +0600 Subject: [PATCH 01/41] Set ExecutionPayload.random to the previous randao_mix --- specs/merge/beacon-chain.md | 8 ++++---- specs/merge/validator.md | 7 +------ specs/sharding/beacon-chain.md | 4 ++-- tests/core/pyspec/eth2spec/test/helpers/block.py | 3 +-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index ed12d3eb6..ee5f59aa8 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -246,15 +246,17 @@ The above function is accessed through the `EXECUTION_ENGINE` module which insta ### Block processing +*Note*: The call to the `process_execution_payload` must happen before the call to `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. + ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) + if is_execution_enabled(state, block.body): + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Merge] process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) - if is_execution_enabled(state, block.body): - process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Merge] ``` ### Execution payload processing @@ -284,8 +286,6 @@ def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader #### `process_execution_payload` -*Note:* This function depends on `process_randao` function call as it retrieves the most recent randao mix from the `state`. Implementations that are considering parallel processing of execution payload with respect to beacon chain state transition function should work around this dependency. - ```python def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: # Verify consistency of the parent hash, block number, random, base fee per gas and gas limit diff --git a/specs/merge/validator.md b/specs/merge/validator.md index efeeca061..e71ee74a8 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -75,17 +75,12 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ return None -def compute_randao_mix(state: BeaconState, randao_reveal: BLSSignature) -> Bytes32: - epoch = get_current_epoch(state) - return xor(get_randao_mix(state, epoch), hash(randao_reveal)) - - def produce_execution_payload(state: BeaconState, parent_hash: Hash32, randao_reveal: BLSSignature, execution_engine: ExecutionEngine) -> ExecutionPayload: timestamp = compute_timestamp_at_slot(state, state.slot) - randao_mix = compute_randao_mix(state, randao_reveal) + randao_mix = get_randao_mix(state, get_current_epoch(state)) return execution_engine.assemble_block(parent_hash, timestamp, randao_mix) diff --git a/specs/sharding/beacon-chain.md b/specs/sharding/beacon-chain.md index f54394275..2c8e8f20b 100644 --- a/specs/sharding/beacon-chain.md +++ b/specs/sharding/beacon-chain.md @@ -552,12 +552,12 @@ def compute_committee_index_from_shard(state: BeaconState, slot: Slot, shard: Sh ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) + # is_execution_enabled is omitted, execution is enabled by default. + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) # [Modified in Sharding] process_sync_aggregate(state, block.body.sync_aggregate) - # is_execution_enabled is omitted, execution is enabled by default. - process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) ``` #### Operations diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index b8f7c4bcb..78b90b165 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -99,8 +99,7 @@ def build_empty_block(spec, state, slot=None): empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY if is_post_merge(spec): - randao_mix = spec.compute_randao_mix(state, empty_block.body.randao_reveal) - empty_block.body.execution_payload = build_empty_execution_payload(spec, state, randao_mix) + empty_block.body.execution_payload = build_empty_execution_payload(spec, state) return empty_block From 02057cb13e5086d259b62d7b3c8ad27effc307dd Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 1 Sep 2021 20:59:16 +0600 Subject: [PATCH 02/41] Fix spelling --- specs/merge/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index ee5f59aa8..2e7d26954 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -246,7 +246,7 @@ The above function is accessed through the `EXECUTION_ENGINE` module which insta ### Block processing -*Note*: The call to the `process_execution_payload` must happen before the call to `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. +*Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: From 960a49afc9629d96f853242f5fe4a268e0ddeeb3 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 10 Sep 2021 16:07:26 +0600 Subject: [PATCH 03/41] Verify terminal PoW block after call to state_transition --- setup.py | 3 +-- specs/merge/fork-choice.md | 21 +++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 281e292dc..6e55cfdde 100644 --- a/setup.py +++ b/setup.py @@ -509,8 +509,7 @@ ExecutionState = Any def get_pow_block(hash: Bytes32) -> PowBlock: - return PowBlock(block_hash=hash, parent_hash=Bytes32(), is_valid=True, is_processed=True, - total_difficulty=uint256(0), difficulty=uint256(0)) + return PowBlock(block_hash=hash, parent_hash=Bytes32(), total_difficulty=uint256(0), difficulty=uint256(0)) def get_execution_state(execution_state_root: Bytes32) -> ExecutionState: diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index de82b17fa..84be0f1ce 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -83,8 +83,6 @@ class TransitionStore(object): class PowBlock(object): block_hash: Hash32 parent_hash: Hash32 - is_processed: boolean - is_valid: boolean total_difficulty: uint256 difficulty: uint256 ``` @@ -93,7 +91,7 @@ class PowBlock(object): Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given the hash of the PoW block returns its data. -*Note*: The `eth_getBlockByHash` JSON-RPC method does not distinguish invalid blocks from blocks that haven't been processed yet. Either extending this existing method or implementing a new one is required. +*Note*: The `eth_getBlockByHash` JSON-RPC method may be used to pull this information from an execution client. ### `is_valid_terminal_pow_block` @@ -103,7 +101,7 @@ Used by fork-choice handler, `on_block`. def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlock, parent: PowBlock) -> bool: is_total_difficulty_reached = block.total_difficulty >= transition_store.terminal_total_difficulty is_parent_total_difficulty_valid = parent.total_difficulty < transition_store.terminal_total_difficulty - return block.is_valid and is_total_difficulty_reached and is_parent_total_difficulty_valid + return is_total_difficulty_reached and is_parent_total_difficulty_valid ``` ## Updated fork-choice handlers @@ -128,17 +126,16 @@ def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: Tr # 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 - # [New in Merge] - if (transition_store is not None) and is_merge_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.execution_payload.parent_hash) - pow_parent = get_pow_block(pow_block.parent_hash) - assert pow_block.is_processed - assert is_valid_terminal_pow_block(transition_store, pow_block, pow_parent) - # Check the block is valid and compute the post-state state = pre_state.copy() state_transition(state, signed_block, True) + + # [New in Merge] + if (transition_store is not None) and is_merge_block(pre_state, block.body): + pow_block = get_pow_block(block.body.execution_payload.parent_hash) + pow_parent = get_pow_block(pow_block.parent_hash) + assert is_valid_terminal_pow_block(transition_store, pow_block, pow_parent) + # Add new block to the store store.blocks[hash_tree_root(block)] = block # Add new state for this block to the store From 559ca86e2a6eefa1dc4aa4e48b2deede55f5d268 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 10 Sep 2021 16:56:27 +0200 Subject: [PATCH 04/41] "is build" -> "is built" typo Corrects a typo in a Makefile comment. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9f32b4568..977141078 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ define run_generator echo "generator $(1) finished" endef -# The tests dir itself is simply build by creating the directory (recursively creating deeper directories if necessary) +# The tests dir itself is simply built by creating the directory (recursively creating deeper directories if necessary) $(TEST_VECTOR_DIR): $(info creating test output directory, for generators: ${GENERATOR_TARGETS}) mkdir -p $@ From 899bde08734c3ebe72340226cab808fb563c4f84 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Mon, 13 Sep 2021 06:31:11 -0700 Subject: [PATCH 05/41] Rename client_settings.md to client-settings.md --- specs/merge/{client_settings.md => client-settings.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename specs/merge/{client_settings.md => client-settings.md} (100%) diff --git a/specs/merge/client_settings.md b/specs/merge/client-settings.md similarity index 100% rename from specs/merge/client_settings.md rename to specs/merge/client-settings.md From 370b9e86e31e966a7f105e1b32018d3602d0dec4 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 15 Sep 2021 21:30:16 +0200 Subject: [PATCH 06/41] pass sync committee sig consistently in tests There are three defined unit tests for the light client sync protocol. They all follow a similar structure. However, there is an inconcistency how they pass the slot to compute_aggregate_sync_committee_signature. In one instance it is passed as `block.slot`. In the other two cases it is passed as `block_header.slot`. As the `block_header` is created from the `block`, they share the same value. This patch makes the way how the slot is passed consistent across all of the test cases. --- .../pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py index a3cf8b7ca..c69957de5 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py @@ -52,7 +52,7 @@ def test_process_light_client_update_not_updated(spec, state): sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, - block.slot, + block_header.slot, committee, ) next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] From 1f486c1b32f8b1b502270e8e5621d222dc5fb158 Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Wed, 15 Sep 2021 18:47:44 -0500 Subject: [PATCH 07/41] fixed client-settings.md link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5a898d37..9e5d7dc42 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ The merge is still actively in development. The exact specification has not been * [Merge fork](specs/merge/fork.md) * [Fork Choice changes](specs/merge/fork-choice.md) * [Validator additions](specs/merge/validator.md) - * [Client settings](specs/merge/client_settings.md) + * [Client settings](specs/merge/client-settings.md) ### Sharding From 6f78e6a3eeb87276133e87e6e9d21bb0c47518d9 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 16 Sep 2021 11:28:04 +0600 Subject: [PATCH 08/41] Remove randao_reveal from validator.md --- specs/merge/validator.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index e71ee74a8..b7a2860fd 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -77,7 +77,6 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ def produce_execution_payload(state: BeaconState, parent_hash: Hash32, - randao_reveal: BLSSignature, execution_engine: ExecutionEngine) -> ExecutionPayload: timestamp = compute_timestamp_at_slot(state, state.slot) randao_mix = get_randao_mix(state, get_current_epoch(state)) @@ -86,7 +85,6 @@ def produce_execution_payload(state: BeaconState, def get_execution_payload(state: BeaconState, transition_store: TransitionStore, - randao_reveal: BLSSignature, execution_engine: ExecutionEngine, pow_chain: Sequence[PowBlock]) -> ExecutionPayload: if not is_merge_complete(state): @@ -96,9 +94,9 @@ def get_execution_payload(state: BeaconState, return ExecutionPayload() else: # Signify merge via producing on top of the last PoW block - return produce_execution_payload(state, terminal_pow_block.block_hash, randao_reveal, execution_engine) + return produce_execution_payload(state, terminal_pow_block.block_hash, execution_engine) # Post-merge, normal payload parent_hash = state.latest_execution_payload_header.block_hash - return produce_execution_payload(state, parent_hash, randao_reveal, execution_engine) + return produce_execution_payload(state, parent_hash, execution_engine) ``` From 26c78b540a2479a909c4543f0642aca27d3d7d95 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 17 Sep 2021 16:01:15 +0600 Subject: [PATCH 09/41] Fix test_blocks#test_parent_from_same_slot --- .../pyspec/eth2spec/test/phase0/sanity/test_blocks.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index 6866a86ae..8ff6bd731 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -143,6 +143,9 @@ def process_and_sign_block_without_header_validations(spec, state, block): state_root=spec.Bytes32(), body_root=block.body.hash_tree_root(), ) + if is_post_merge(spec): + if spec.is_execution_enabled(state, block.body): + spec.process_execution_payload(state, block.body.execution_payload, spec.EXECUTION_ENGINE) # Perform rest of process_block transitions spec.process_randao(state, block.body) @@ -150,9 +153,6 @@ def process_and_sign_block_without_header_validations(spec, state, block): spec.process_operations(state, block.body) if is_post_altair(spec): spec.process_sync_aggregate(state, block.body.sync_aggregate) - if is_post_merge(spec): - if spec.is_execution_enabled(state, block.body): - spec.process_execution_payload(state, block.body.execution_payload, spec.EXECUTION_ENGINE) # Insert post-state rot block.state_root = state.hash_tree_root() @@ -196,8 +196,7 @@ def test_parent_from_same_slot(spec, state): child_block.parent_root = state.latest_block_header.hash_tree_root() if is_post_merge(spec): - randao_mix = spec.compute_randao_mix(state, child_block.body.randao_reveal) - child_block.body.execution_payload = build_empty_execution_payload(spec, state, randao_mix) + child_block.body.execution_payload = build_empty_execution_payload(spec, state) # Show that normal path through transition fails failed_state = state.copy() From d0889b9001e006173dfe3679196efd5abf7fd7cb Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 17 Sep 2021 16:20:25 +0600 Subject: [PATCH 10/41] Hardcode terminal total difficulty --- configs/mainnet.yaml | 3 --- configs/minimal.yaml | 3 --- specs/merge/beacon-chain.md | 7 +++++++ specs/merge/client-settings.md | 9 ++------- specs/merge/fork-choice.md | 21 ++++++-------------- specs/merge/fork.md | 35 ---------------------------------- specs/merge/validator.md | 5 ++--- 7 files changed, 17 insertions(+), 66 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index dd5b394af..aa1858b69 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -31,9 +31,6 @@ MERGE_FORK_EPOCH: 18446744073709551615 SHARDING_FORK_VERSION: 0x03000000 SHARDING_FORK_EPOCH: 18446744073709551615 -# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. -MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296 - # Time parameters # --------------------------------------------------------------- diff --git a/configs/minimal.yaml b/configs/minimal.yaml index b067f222f..9f5cdbe32 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -30,9 +30,6 @@ MERGE_FORK_EPOCH: 18446744073709551615 SHARDING_FORK_VERSION: 0x03000001 SHARDING_FORK_EPOCH: 18446744073709551615 -# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. -MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296 - # Time parameters # --------------------------------------------------------------- diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 2e7d26954..75a667b34 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -14,6 +14,7 @@ - [Execution](#execution) - [Configuration](#configuration) - [Genesis testing settings](#genesis-testing-settings) + - [Transition](#transition) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) @@ -76,6 +77,12 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | `GENESIS_GAS_LIMIT` | `uint64(30000000)` (= 30,000,000) | | `GENESIS_BASE_FEE_PER_GAS` | `Bytes32('0x00ca9a3b00000000000000000000000000000000000000000000000000000000')` (= 1,000,000,000) | +### Transition settings + +| Name | Value | +| - | - | +| `TERMINAL_TOTAL_DIFFICULTY` | `uint256(2**256 - 1)` | + ## Containers ### Extended containers diff --git a/specs/merge/client-settings.md b/specs/merge/client-settings.md index a8ca633ff..64b2b20e6 100644 --- a/specs/merge/client-settings.md +++ b/specs/merge/client-settings.md @@ -15,12 +15,7 @@ This document specifies configurable settings that clients must implement for th ### Override terminal total difficulty -To coordinate manual overrides to [`terminal_total_difficulty`](fork-choice.md#transitionstore), clients -must provide `--terminal-total-difficulty-override` as a configurable setting. +To coordinate manual overrides to [`TERMINAL_TOTAL_DIFFICULTY`](./beacon-chain.md#Transition-settings) parameter, clients must provide `--terminal-total-difficulty-override` as a configurable setting. The value provided by this setting must take precedence over pre-configured `TERMINAL_TOTAL_DIFFICULTY` parameter. -If `TransitionStore` has already [been initialized](./fork.md#initializing-transition-store), this alters the previously initialized value of -`TransitionStore.terminal_total_difficulty`, otherwise this setting initializes `TransitionStore` with the specified, bypassing `compute_terminal_total_difficulty` and the use of an `anchor_pow_block`. -`terminal_total_difficulty`. +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. -Except under exceptional scenarios, this setting is expected to not be used, and `terminal_total_difficulty` will operate with [default functionality](./fork.md#initializing-transition-store). Sufficient warning to the user about this exceptional configurable setting should be provided. -[here](fork.md#initializing-transition-store). diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 84be0f1ce..8051ab3eb 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -13,7 +13,6 @@ - [`set_head`](#set_head) - [`finalize_block`](#finalize_block) - [Helpers](#helpers) - - [`TransitionStore`](#transitionstore) - [`PowBlock`](#powblock) - [`get_pow_block`](#get_pow_block) - [`is_valid_terminal_pow_block`](#is_valid_terminal_pow_block) @@ -68,14 +67,6 @@ def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool: ## Helpers -### `TransitionStore` - -```python -@dataclass -class TransitionStore(object): - terminal_total_difficulty: uint256 -``` - ### `PowBlock` ```python @@ -98,9 +89,9 @@ Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given t Used by fork-choice handler, `on_block`. ```python -def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlock, parent: PowBlock) -> bool: - is_total_difficulty_reached = block.total_difficulty >= transition_store.terminal_total_difficulty - is_parent_total_difficulty_valid = parent.total_difficulty < transition_store.terminal_total_difficulty +def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool: + 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 ``` @@ -111,7 +102,7 @@ def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlo *Note*: The only modification is the addition of the verification of transition block conditions. ```python -def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: TransitionStore=None) -> None: +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 @@ -131,10 +122,10 @@ def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: Tr state_transition(state, signed_block, True) # [New in Merge] - if (transition_store is not None) and is_merge_block(pre_state, block.body): + if is_merge_block(pre_state, block.body): pow_block = get_pow_block(block.body.execution_payload.parent_hash) pow_parent = get_pow_block(pow_block.parent_hash) - assert is_valid_terminal_pow_block(transition_store, pow_block, pow_parent) + assert is_valid_terminal_pow_block(pow_block, pow_parent) # Add new block to the store store.blocks[hash_tree_root(block)] = block diff --git a/specs/merge/fork.md b/specs/merge/fork.md index f2547758d..eb0ca91c6 100644 --- a/specs/merge/fork.md +++ b/specs/merge/fork.md @@ -12,7 +12,6 @@ - [Fork to Merge](#fork-to-merge) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) - - [Initializing transition store](#initializing-transition-store) @@ -28,8 +27,6 @@ Warning: this configuration is not definitive. | - | - | | `MERGE_FORK_VERSION` | `Version('0x02000000')` | | `MERGE_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | -| `MIN_ANCHOR_POW_BLOCK_DIFFICULTY` | **TBD** | -| `TARGET_SECONDS_TO_MERGE` | `uint64(7 * 86400)` = (604,800) | ## Fork to Merge @@ -37,8 +34,6 @@ Warning: this configuration is not definitive. TBD. Social consensus, along with state conditions such as epoch boundary, finality, deposits, active validator count, etc. may be part of the decision process to trigger the fork. For now we assume the condition will be triggered at epoch `MERGE_FORK_EPOCH`. -Since the Merge transition process relies on `Eth1Data` in the beacon state we do want to make sure that this data is fresh. This is achieved by forcing `MERGE_FORK_EPOCH` to point to eth1 voting period boundary, i.e. `MERGE_FORK_EPOCH` should satisfy the following condition `MERGE_FORK_EPOCH % EPOCHS_PER_ETH1_VOTING_PERIOD == 0`. - Note that for the pure Merge networks, we don't apply `upgrade_to_merge` since it starts with Merge version logic. ### Upgrading the state @@ -100,33 +95,3 @@ def upgrade_to_merge(pre: altair.BeaconState) -> BeaconState: return post ``` - -### Initializing transition store - -If `state.slot % SLOTS_PER_EPOCH == 0`, `compute_epoch_at_slot(state.slot) == MERGE_FORK_EPOCH`, and the transition store has not already been initialized, a transition store is initialized to be further utilized by the transition process of the Merge. - -Transition store initialization occurs after the state has been modified by corresponding `upgrade_to_merge` function. - -```python -def compute_terminal_total_difficulty(anchor_pow_block: PowBlock) -> uint256: - seconds_per_voting_period = EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH * SECONDS_PER_SLOT - pow_blocks_per_voting_period = seconds_per_voting_period // SECONDS_PER_ETH1_BLOCK - pow_blocks_to_merge = TARGET_SECONDS_TO_MERGE // SECONDS_PER_ETH1_BLOCK - pow_blocks_after_anchor_block = ETH1_FOLLOW_DISTANCE + pow_blocks_per_voting_period + pow_blocks_to_merge - anchor_difficulty = max(MIN_ANCHOR_POW_BLOCK_DIFFICULTY, anchor_pow_block.difficulty) - - return anchor_pow_block.total_difficulty + anchor_difficulty * pow_blocks_after_anchor_block - - -def get_transition_store(anchor_pow_block: PowBlock) -> TransitionStore: - terminal_total_difficulty = compute_terminal_total_difficulty(anchor_pow_block) - return TransitionStore(terminal_total_difficulty=terminal_total_difficulty) - - -def initialize_transition_store(state: BeaconState) -> TransitionStore: - pow_block = get_pow_block(state.eth1_data.block_hash) - return get_transition_store(pow_block) -``` - -*Note*: Transition store can also be initialized at client startup by [overriding terminal total -difficulty](client_settings.md#override-terminal-total-difficulty). diff --git a/specs/merge/validator.md b/specs/merge/validator.md index b7a2860fd..645e1967b 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -62,7 +62,7 @@ All validator responsibilities remain unchanged other than those noted below. Na ##### Execution Payload -* Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine, pow_chain)` where: +* Set `block.body.execution_payload = get_execution_payload(state, execution_engine, pow_chain)` where: ```python def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequence[PowBlock]) -> Optional[PowBlock]: @@ -84,11 +84,10 @@ def produce_execution_payload(state: BeaconState, def get_execution_payload(state: BeaconState, - transition_store: TransitionStore, execution_engine: ExecutionEngine, pow_chain: Sequence[PowBlock]) -> ExecutionPayload: if not is_merge_complete(state): - terminal_pow_block = get_pow_block_at_total_difficulty(transition_store.terminal_total_difficulty, pow_chain) + terminal_pow_block = get_pow_block_at_total_difficulty(TERMINAL_TOTAL_DIFFICULTY, pow_chain) if terminal_pow_block is None: # Pre-merge, empty payload return ExecutionPayload() From a48ea83ab80f270e729c3d57b68d38080889d4fe Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 17 Sep 2021 16:54:06 +0600 Subject: [PATCH 11/41] Fix toc --- specs/merge/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 75a667b34..a9eea2f4a 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -14,7 +14,7 @@ - [Execution](#execution) - [Configuration](#configuration) - [Genesis testing settings](#genesis-testing-settings) - - [Transition](#transition) + - [Transition settings](#transition-settings) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) From c2084ad5b010de955a2b58430134678fb8e738df Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 17 Sep 2021 18:23:21 +0600 Subject: [PATCH 12/41] Bring on extra_data field --- specs/merge/beacon-chain.md | 4 ++++ tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index ed12d3eb6..a2a37e215 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -64,6 +64,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | `BYTES_PER_LOGS_BLOOM` | `uint64(2**8)` (= 256) | | `GAS_LIMIT_DENOMINATOR` | `uint64(2**10)` (= 1,024) | | `MIN_GAS_LIMIT` | `uint64(5000)` (= 5,000) | +| `MAX_EXTRA_DATA_BYTES` | `2**5` (= 32) | ## Configuration @@ -159,6 +160,7 @@ class ExecutionPayload(Container): gas_limit: uint64 gas_used: uint64 timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: Bytes32 # base fee introduced in EIP-1559, little-endian serialized # Extra payload fields block_hash: Hash32 # Hash of execution block @@ -180,6 +182,7 @@ class ExecutionPayloadHeader(Container): gas_limit: uint64 gas_used: uint64 timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: Bytes32 # Extra payload fields block_hash: Hash32 # Hash of execution block @@ -310,6 +313,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe gas_limit=payload.gas_limit, gas_used=payload.gas_used, timestamp=payload.timestamp, + extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 43be965a5..6126346a9 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -20,6 +20,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None): gas_limit=latest.gas_limit, # retain same limit gas_used=0, # empty block, 0 gas timestamp=timestamp, + extra_data=spec.ByteList[spec.MAX_EXTRA_DATA_BYTES](), base_fee_per_gas=latest.base_fee_per_gas, # retain same base_fee block_hash=spec.Hash32(), transactions=empty_txs, @@ -42,6 +43,7 @@ def get_execution_payload_header(spec, execution_payload): gas_limit=execution_payload.gas_limit, gas_used=execution_payload.gas_used, timestamp=execution_payload.timestamp, + extra_data=execution_payload.extra_data, base_fee_per_gas=execution_payload.base_fee_per_gas, block_hash=execution_payload.block_hash, transactions_root=spec.hash_tree_root(execution_payload.transactions) From 3ef13561e68ee3522e481a587cf3ad3b702849e0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 17 Sep 2021 11:00:32 -0600 Subject: [PATCH 13/41] ensure random is validated for all payloads including transition --- specs/merge/beacon-chain.md | 6 ++-- .../test_process_execution_payload.py | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a2a37e215..4a9fb8a5f 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -291,12 +291,14 @@ def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader ```python def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: - # Verify consistency of the parent hash, block number, random, base fee per gas and gas limit + # Verify consistency of the parent hash, block number, base fee per gas and gas limit + # with respect to the previous execution payload header if is_merge_complete(state): assert payload.parent_hash == state.latest_execution_payload_header.block_hash assert payload.block_number == state.latest_execution_payload_header.block_number + uint64(1) - assert payload.random == get_randao_mix(state, get_current_epoch(state)) assert is_valid_gas_limit(payload, state.latest_execution_payload_header) + # Verify random + assert payload.random == get_randao_mix(state, get_current_epoch(state)) # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify the execution payload is valid diff --git a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py index 4c68034d4..9c5ed6712 100644 --- a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py @@ -144,6 +144,34 @@ def test_bad_parent_hash_regular_payload(spec, state): yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) +@with_merge_and_later +@spec_state_test +def test_bad_random_first_payload(spec, state): + # pre-state + state = build_state_with_incomplete_transition(spec, state) + next_slot(spec, state) + + # execution payload + execution_payload = build_empty_execution_payload(spec, state) + execution_payload.random = b'\x42' * 32 + + yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) + + +@with_merge_and_later +@spec_state_test +def test_bad_random_regular_payload(spec, state): + # pre-state + state = build_state_with_complete_transition(spec, state) + next_slot(spec, state) + + # execution payload + execution_payload = build_empty_execution_payload(spec, state) + execution_payload.random = b'\x04' * 32 + + yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) + + @with_merge_and_later @spec_state_test def test_bad_number_regular_payload(spec, state): From 9ca8c592c5b7074b8fa2cea6cf14b63bea46f360 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Sat, 18 Sep 2021 12:39:54 +0600 Subject: [PATCH 14/41] Add TBD for TTD and add the value to the configs --- configs/mainnet.yaml | 6 ++++++ configs/minimal.yaml | 6 ++++++ specs/merge/beacon-chain.md | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index aa1858b69..6f2f582fa 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -3,6 +3,12 @@ # Extends the mainnet preset PRESET_BASE: 'mainnet' +# Transition +# --------------------------------------------------------------- +# TBD, 2**256-1 is a placeholder +TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129639935 + + # Genesis # --------------------------------------------------------------- # `2**14` (= 16,384) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 9f5cdbe32..8da3260f5 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -3,6 +3,12 @@ # Extends the minimal preset PRESET_BASE: 'minimal' +# Transition +# --------------------------------------------------------------- +# TBD, 2**256-1 is a placeholder +TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129639935 + + # Genesis # --------------------------------------------------------------- # [customized] diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a9eea2f4a..03bf01155 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -81,7 +81,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | Name | Value | | - | - | -| `TERMINAL_TOTAL_DIFFICULTY` | `uint256(2**256 - 1)` | +| `TERMINAL_TOTAL_DIFFICULTY` | **TBD** | ## Containers From b530e017619b79b7a8c4d9105177c3425d5d9770 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 20 Sep 2021 20:57:45 +0600 Subject: [PATCH 15/41] Update calls to execution_engine --- setup.py | 19 ++-- specs/merge/beacon-chain.md | 28 ++++-- specs/merge/fork-choice.md | 32 ++----- specs/merge/validator.md | 92 +++++++++++++------ .../test_process_execution_payload.py | 2 +- 5 files changed, 107 insertions(+), 66 deletions(-) diff --git a/setup.py b/setup.py index 6e55cfdde..1d647c2a1 100644 --- a/setup.py +++ b/setup.py @@ -522,16 +522,23 @@ def get_pow_chain_head() -> PowBlock: class NoopExecutionEngine(ExecutionEngine): - def on_payload(self, execution_payload: ExecutionPayload) -> bool: + def execute_payload(self, execution_payload: ExecutionPayload) -> bool: return True - def set_head(self, block_hash: Hash32) -> bool: - return True + def consensus_validated(self: ExecutionEngine, execution_payload: ExecutionPayload) -> None: + pass - def finalize_block(self, block_hash: Hash32) -> bool: - return True + def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: + pass - def assemble_block(self, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload: + def prepare_payload(self: ExecutionEngine, + parent_hash: Hash32, + timestamp: uint64, + random: Bytes32, + feeRecipient: Bytes20) -> uint64: + raise NotImplementedError("no default block production") + + def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: raise NotImplementedError("no default block production") diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 03bf01155..a5fc4101d 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -31,7 +31,8 @@ - [`compute_timestamp_at_slot`](#compute_timestamp_at_slot) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Execution engine](#execution-engine) - - [`on_payload`](#on_payload) + - [`execute_payload`](#execute_payload) + - [`consensus_validated`](#consensus_validated) - [Block processing](#block-processing) - [Execution payload processing](#execution-payload-processing) - [`is_valid_gas_limit`](#is_valid_gas_limit) @@ -237,19 +238,31 @@ def compute_timestamp_at_slot(state: BeaconState, slot: Slot) -> uint64: The implementation-dependent `ExecutionEngine` protocol encapsulates the execution sub-system logic via: * a state object `self.execution_state` of type `ExecutionState` -* a state transition function `self.on_payload` which mutates `self.execution_state` +* a state transition function `self.execute_payload` which applies changes to the `self.execution_state` +* a method `self.consensus_validated` which notifies that the block holding the execution payload +is valid with respect to the consensus rule set -#### `on_payload` +#### `execute_payload` ```python -def on_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: +def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: """ Returns ``True`` iff ``execution_payload`` is valid with respect to ``self.execution_state``. """ ... ``` -The above function is accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. +#### `consensus_validated` + +```python +def consensus_validated(self: ExecutionEngine, execution_payload: ExecutionPayload) -> None: + ... +``` + +The above functions are accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. + +The body of each of these functions is implementation dependent. +The Engine API may be used to implement them with an external execution engine. ### Block processing @@ -264,6 +277,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) + if is_execution_enabled(state, block.body): + # Notify the block is valid with respect to the consensus state transition function + EXECUTION_ENGINE.consensus_validated(block.body.execution_payload) # [New in Merge] ``` ### Execution payload processing @@ -304,7 +320,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify the execution payload is valid - assert execution_engine.on_payload(payload) + assert execution_engine.execute_payload(payload) # Cache execution payload header state.latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 8051ab3eb..d8b3426ea 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -10,8 +10,7 @@ - [Introduction](#introduction) - [Protocols](#protocols) - [`ExecutionEngine`](#executionengine) - - [`set_head`](#set_head) - - [`finalize_block`](#finalize_block) + - [`forkchoice_updated`](#forkchoice_updated) - [Helpers](#helpers) - [`PowBlock`](#powblock) - [`get_pow_block`](#get_pow_block) @@ -34,36 +33,19 @@ This is the modification of the fork choice according to the executable beacon c The following methods are added to the `ExecutionEngine` protocol for use in the fork choice: -#### `set_head` +#### `forkchoice_updated` -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. +* Re-organizes the execution payload chain and corresponding state to make `head_block_hash` the head. +* Applies finality to the execution state: it irreversibly persists the chain of all execution payloads +and corresponding state, up to and including `finalized_block_hash`. ```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. - """ +def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: ... ``` -#### `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. - """ - ... -``` +The Engine API may be used to implement this with an external execution engine. ## Helpers diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 645e1967b..7dfcecbc1 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -12,11 +12,12 @@ - [Prerequisites](#prerequisites) - [Protocols](#protocols) - [`ExecutionEngine`](#executionengine) - - [`assemble_block`](#assemble_block) + - [`prepare_payload`](#prepare_payload) + - [`get_payload`](#get_payload) - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [Execution Payload](#execution-payload) + - [ExecutionPayload](#executionpayload) @@ -39,19 +40,39 @@ Please see related Beacon Chain doc before continuing and use them as a referenc The following methods are added to the `ExecutionEngine` protocol for use as a validator: -#### `assemble_block` +#### `prepare_payload` -Produces a new instance of an execution payload, with the specified `timestamp`, -on top of the execution payload chain tip identified by `block_hash`. - -The body of this function is implementation dependent. -The Consensus API may be used to implement this with an external execution engine. +Given the set of execution payload attributes initiates a process of building an execution payload +on top of the execution chain tip identified by `parent_hash`. ```python -def assemble_block(self: ExecutionEngine, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload: +def prepare_payload(self: ExecutionEngine, + parent_hash: Hash32, + timestamp: uint64, + random: Bytes32, + fee_recipient: Bytes20) -> uint64: + """ + Returns ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call. + """ ... ``` +#### `get_payload` + +Given the `payload_id` returns the most recent version of the execution payload that +has been built since the corresponding call to `prepare_payload` method. + +```python +def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: + """ + Returns ``execution_payload`` object. + """ + ... +``` + +The body of each of these functions is implementation dependent. +The Engine API may be used to implement them with an external execution engine. + ## Beacon chain responsibilities All validator responsibilities remain unchanged other than those noted below. Namely, the transition block handling and the addition of `ExecutionPayload`. @@ -60,9 +81,14 @@ All validator responsibilities remain unchanged other than those noted below. Na #### Constructing the `BeaconBlockBody` -##### Execution Payload +##### ExecutionPayload -* Set `block.body.execution_payload = get_execution_payload(state, execution_engine, pow_chain)` where: +To obtain an execution payload a proposer of a block must take the following actions: + +1. Set `payload_id = prepare_execution_payload(state, pow_chain, fee_recipient, execution_engine)`, where: + * `state` is the state for which `is_proposer(state, validator_index)` returns `True` + * `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]: @@ -75,27 +101,37 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ return None -def produce_execution_payload(state: BeaconState, - parent_hash: Hash32, - execution_engine: ExecutionEngine) -> ExecutionPayload: - timestamp = compute_timestamp_at_slot(state, state.slot) - randao_mix = get_randao_mix(state, get_current_epoch(state)) - return execution_engine.assemble_block(parent_hash, timestamp, randao_mix) - - -def get_execution_payload(state: BeaconState, - execution_engine: ExecutionEngine, - pow_chain: Sequence[PowBlock]) -> ExecutionPayload: +def prepare_execution_payload(state: BeaconState, + pow_chain: Sequence[PowBlock], + fee_recipient: Bytes20, + execution_engine: ExecutionEngine) -> Optional[uint64]: if not is_merge_complete(state): terminal_pow_block = get_pow_block_at_total_difficulty(TERMINAL_TOTAL_DIFFICULTY, pow_chain) if terminal_pow_block is None: - # Pre-merge, empty payload - return ExecutionPayload() + # Pre-merge, no prepare payload call is needed + return None else: # Signify merge via producing on top of the last PoW block - return produce_execution_payload(state, terminal_pow_block.block_hash, execution_engine) + parent_hash = terminal_pow_block.block_hash + else: + # Post-merge, normal payload + parent_hash = state.latest_execution_payload_header.block_hash - # Post-merge, normal payload - parent_hash = state.latest_execution_payload_header.block_hash - return produce_execution_payload(state, parent_hash, execution_engine) + timestamp = compute_timestamp_at_slot(state, state.slot) + random = get_randao_mix(state, get_current_epoch(state)) + return execution_engine.prepare_payload(parent_hash, timestamp, random, fee_recipient) ``` + +2. Set `block.body.execution_payload = get_execution_payload(payload_id, execution_engine)`, where: + +```python +def get_execution_payload(payload_id: Optional[uint64], execution_engine: ExecutionEngine) -> ExecutionPayload: + if payload_id is None: + # Pre-merge, empty payload + return ExecutionPayload() + else: + return execution_engine.get_payload(payload_id) +``` + +*Note*: It is recommended for a validator to call `prepare_execution_payload` as soon as input parameters become known, +and make subsequent calls to this function if any of these parameters has been updated. diff --git a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py index 4c68034d4..a3aadc470 100644 --- a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py @@ -25,7 +25,7 @@ def run_execution_payload_processing(spec, state, execution_payload, valid=True, called_new_block = False class TestEngine(spec.NoopExecutionEngine): - def on_payload(self, payload) -> bool: + def execute_payload(self, payload) -> bool: nonlocal called_new_block, execution_valid called_new_block = True assert payload == execution_payload From cb9e65ab85602661d9625af002247f772453581b Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 17 Sep 2021 18:23:21 +0600 Subject: [PATCH 16/41] Bring on extra_data field --- specs/merge/beacon-chain.md | 4 ++++ tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 03bf01155..4f89908fd 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -65,6 +65,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | `BYTES_PER_LOGS_BLOOM` | `uint64(2**8)` (= 256) | | `GAS_LIMIT_DENOMINATOR` | `uint64(2**10)` (= 1,024) | | `MIN_GAS_LIMIT` | `uint64(5000)` (= 5,000) | +| `MAX_EXTRA_DATA_BYTES` | `2**5` (= 32) | ## Configuration @@ -166,6 +167,7 @@ class ExecutionPayload(Container): gas_limit: uint64 gas_used: uint64 timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: Bytes32 # base fee introduced in EIP-1559, little-endian serialized # Extra payload fields block_hash: Hash32 # Hash of execution block @@ -187,6 +189,7 @@ class ExecutionPayloadHeader(Container): gas_limit: uint64 gas_used: uint64 timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: Bytes32 # Extra payload fields block_hash: Hash32 # Hash of execution block @@ -317,6 +320,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe gas_limit=payload.gas_limit, gas_used=payload.gas_used, timestamp=payload.timestamp, + extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 43be965a5..6126346a9 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -20,6 +20,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None): gas_limit=latest.gas_limit, # retain same limit gas_used=0, # empty block, 0 gas timestamp=timestamp, + extra_data=spec.ByteList[spec.MAX_EXTRA_DATA_BYTES](), base_fee_per_gas=latest.base_fee_per_gas, # retain same base_fee block_hash=spec.Hash32(), transactions=empty_txs, @@ -42,6 +43,7 @@ def get_execution_payload_header(spec, execution_payload): gas_limit=execution_payload.gas_limit, gas_used=execution_payload.gas_used, timestamp=execution_payload.timestamp, + extra_data=execution_payload.extra_data, base_fee_per_gas=execution_payload.base_fee_per_gas, block_hash=execution_payload.block_hash, transactions_root=spec.hash_tree_root(execution_payload.transactions) From 731bcad3175f36d1d99d1343b49e0584cae1ad8e Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Wed, 15 Sep 2021 18:47:44 -0500 Subject: [PATCH 17/41] fixed client-settings.md link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5a898d37..9e5d7dc42 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ The merge is still actively in development. The exact specification has not been * [Merge fork](specs/merge/fork.md) * [Fork Choice changes](specs/merge/fork-choice.md) * [Validator additions](specs/merge/validator.md) - * [Client settings](specs/merge/client_settings.md) + * [Client settings](specs/merge/client-settings.md) ### Sharding From e2af59c8cd5557de68d0dd890f04e337cd58e7d3 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 17 Sep 2021 11:00:32 -0600 Subject: [PATCH 18/41] ensure random is validated for all payloads including transition --- specs/merge/beacon-chain.md | 6 ++-- .../test_process_execution_payload.py | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 4f89908fd..39f457252 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -298,12 +298,14 @@ def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader ```python def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: - # Verify consistency of the parent hash, block number, random, base fee per gas and gas limit + # Verify consistency of the parent hash, block number, base fee per gas and gas limit + # with respect to the previous execution payload header if is_merge_complete(state): assert payload.parent_hash == state.latest_execution_payload_header.block_hash assert payload.block_number == state.latest_execution_payload_header.block_number + uint64(1) - assert payload.random == get_randao_mix(state, get_current_epoch(state)) assert is_valid_gas_limit(payload, state.latest_execution_payload_header) + # Verify random + assert payload.random == get_randao_mix(state, get_current_epoch(state)) # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify the execution payload is valid diff --git a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py index 4c68034d4..9c5ed6712 100644 --- a/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/merge/block_processing/test_process_execution_payload.py @@ -144,6 +144,34 @@ def test_bad_parent_hash_regular_payload(spec, state): yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) +@with_merge_and_later +@spec_state_test +def test_bad_random_first_payload(spec, state): + # pre-state + state = build_state_with_incomplete_transition(spec, state) + next_slot(spec, state) + + # execution payload + execution_payload = build_empty_execution_payload(spec, state) + execution_payload.random = b'\x42' * 32 + + yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) + + +@with_merge_and_later +@spec_state_test +def test_bad_random_regular_payload(spec, state): + # pre-state + state = build_state_with_complete_transition(spec, state) + next_slot(spec, state) + + # execution payload + execution_payload = build_empty_execution_payload(spec, state) + execution_payload.random = b'\x04' * 32 + + yield from run_execution_payload_processing(spec, state, execution_payload, valid=False) + + @with_merge_and_later @spec_state_test def test_bad_number_regular_payload(spec, state): From b292f0b7b384ae9690c958b4a219043e75977448 Mon Sep 17 00:00:00 2001 From: Anton Nashatyrev Date: Tue, 21 Sep 2021 18:04:39 +0300 Subject: [PATCH 19/41] Remove beacon_block_root field from ShardBlob --- specs/sharding/beacon-chain.md | 8 -------- specs/sharding/p2p-interface.md | 15 --------------- 2 files changed, 23 deletions(-) diff --git a/specs/sharding/beacon-chain.md b/specs/sharding/beacon-chain.md index 2c8e8f20b..8190951b4 100644 --- a/specs/sharding/beacon-chain.md +++ b/specs/sharding/beacon-chain.md @@ -270,8 +270,6 @@ class ShardBlobBody(Container): degree_proof: BLSCommitment # The actual data. Should match the commitment and degree proof. data: List[BLSPoint, POINTS_PER_SAMPLE * MAX_SAMPLES_PER_BLOB] - # Latest block root of the Beacon Chain, before shard_blob.slot - beacon_block_root: Root # fee payment fields (EIP 1559 like) # TODO: express in MWei instead? max_priority_fee_per_sample: Gwei @@ -293,8 +291,6 @@ class ShardBlobBodySummary(Container): degree_proof: BLSCommitment # Hash-tree-root as summary of the data field data_root: Root - # Latest block root of the Beacon Chain, before shard_blob.slot - beacon_block_root: Root # fee payment fields (EIP 1559 like) # TODO: express in MWei instead? max_priority_fee_per_sample: Gwei @@ -695,10 +691,6 @@ def process_shard_header(state: BeaconState, signed_header: SignedShardBlobHeade committees_per_slot = get_committee_count_per_slot(state, header_epoch) assert committee_index <= committees_per_slot - # Verify that the block root matches, - # to ensure the header will only be included in this specific Beacon Chain sub-tree. - assert header.body_summary.beacon_block_root == get_block_root_at_slot(state, slot - 1) - # Check that this data is still pending committee_work = state.shard_buffer[slot % SHARD_STATE_MEMORY_SLOTS][shard] assert committee_work.status.selector == SHARD_WORK_PENDING diff --git a/specs/sharding/p2p-interface.md b/specs/sharding/p2p-interface.md index c47d2ee07..76a806635 100644 --- a/specs/sharding/p2p-interface.md +++ b/specs/sharding/p2p-interface.md @@ -97,11 +97,6 @@ on the horizontal subnet or creating samples for it. Alias `blob = signed_blob.m - _[REJECT]_ The blob builder defined by `blob.builder_index` exists and has sufficient balance to back the fee payment. - _[REJECT]_ The blob signature, `signed_blob.signature`, is valid for the aggregate of proposer and builder -- i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob.signature)`. -- _[REJECT]_ The blob is proposed by the expected `proposer_index` for the blob's `slot` and `shard`, - in the context of the current shuffling (defined by `blob.body.beacon_block_root`/`slot`). - If the `proposer_index` cannot immediately be verified against the expected shuffling, - the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- - in such a case _do not_ `REJECT`, instead `IGNORE` this message. #### Global topics @@ -132,11 +127,6 @@ The following validations MUST pass before forwarding the `signed_blob_header` o - _[REJECT]_ The blob builder defined by `blob.builder_index` exists and has sufficient balance to back the fee payment. - _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for the aggregate of proposer and builder -- i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob_header.signature)`. -- _[REJECT]_ The header is proposed by the expected `proposer_index` for the blob's `header.slot` and `header.shard` - in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`). - If the `proposer_index` cannot immediately be verified against the expected shuffling, - the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- - in such a case _do not_ `REJECT`, instead `IGNORE` this message. ##### `shard_blob_tx` @@ -160,11 +150,6 @@ The following validations MUST pass before forwarding the `signed_blob_header` o Propagating nodes MAY increase fee increments in case of spam. - _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for ONLY the builder -- i.e. `bls.Verify(builder_pubkey, blob_signing_root, signed_blob_header.signature)`. The signature is not an aggregate with the proposer. -- _[REJECT]_ The header is designated for proposal by the expected `proposer_index` for the blob's `header.slot` and `header.shard` - in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`). - If the `proposer_index` cannot immediately be verified against the expected shuffling, - the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- - in such a case _do not_ `REJECT`, instead `IGNORE` this message. ##### `shard_proposer_slashing` From 18bfe3555f7b6b7f856096af0678085fdde30357 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 22 Sep 2021 17:45:26 +0600 Subject: [PATCH 20/41] Apply suggestions from code review Co-authored-by: Danny Ryan --- specs/merge/beacon-chain.md | 2 +- specs/merge/fork-choice.md | 1 + specs/merge/validator.md | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a5fc4101d..6a5a2730b 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -239,7 +239,7 @@ The implementation-dependent `ExecutionEngine` protocol encapsulates the executi * a state object `self.execution_state` of type `ExecutionState` * a state transition function `self.execute_payload` which applies changes to the `self.execution_state` -* a method `self.consensus_validated` which notifies that the block holding the execution payload +* a method `self.consensus_validated` which signals that the beacon block containing the execution payload is valid with respect to the consensus rule set #### `execute_payload` diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index d8b3426ea..15d47a650 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -35,6 +35,7 @@ The following methods are added to the `ExecutionEngine` protocol for use in the #### `forkchoice_updated` +This method performs two actions *atomically*: * Re-organizes the execution payload chain and corresponding state to make `head_block_hash` the head. * Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including `finalized_block_hash`. diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 7dfcecbc1..a84384dd6 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -42,7 +42,7 @@ The following methods are added to the `ExecutionEngine` protocol for use as a v #### `prepare_payload` -Given the set of execution payload attributes initiates a process of building an execution payload +Given the set of execution payload attributes, `prepare_payload` initiates a process of building an execution payload on top of the execution chain tip identified by `parent_hash`. ```python @@ -59,7 +59,7 @@ def prepare_payload(self: ExecutionEngine, #### `get_payload` -Given the `payload_id` returns the most recent version of the execution payload that +Given the `payload_id`, `get_payload` returns the most recent version of the execution payload that has been built since the corresponding call to `prepare_payload` method. ```python @@ -83,7 +83,7 @@ All validator responsibilities remain unchanged other than those noted below. Na ##### ExecutionPayload -To obtain an execution payload a proposer of a block must take the following actions: +To obtain an execution payload, the proposer of a block must take the following actions: 1. Set `payload_id = prepare_execution_payload(state, pow_chain, fee_recipient, execution_engine)`, where: * `state` is the state for which `is_proposer(state, validator_index)` returns `True` From 41c12bfcb2e7b97d3e371ecbd8987bd5e549d6e7 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 22 Sep 2021 14:15:07 +0200 Subject: [PATCH 21/41] improve grammar in BLS test comments The comments for the PRIVKEYS definition in the BLS test generator were a bit difficult to read. Improved by rewording them slightly. --- tests/generators/bls/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 75468b162..6fc86d10f 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -45,8 +45,8 @@ MESSAGES = [ SAMPLE_MESSAGE = b'\x12' * 32 PRIVKEYS = [ - # Curve order is 256 so private keys are 32 bytes at most. - # Also not all integers is a valid private key, so using pre-generated keys + # Curve order is 256, so private keys use 32 bytes at most. + # Also, not all integers are valid private keys. Therefore, using pre-generated keys. hex_to_int('0x00000000000000000000000000000000263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3'), hex_to_int('0x0000000000000000000000000000000047b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138'), hex_to_int('0x00000000000000000000000000000000328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216'), From 06107ce7d8be3a66ef40803bca30c808d1cb13c7 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 22 Sep 2021 18:10:57 +0600 Subject: [PATCH 22/41] Polish the description of execution engine functions --- specs/merge/beacon-chain.md | 12 ++++++------ specs/merge/fork-choice.md | 10 +++++----- specs/merge/validator.md | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 3e107b7a9..a1ab61848 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -242,9 +242,14 @@ The implementation-dependent `ExecutionEngine` protocol encapsulates the executi * a state object `self.execution_state` of type `ExecutionState` * a state transition function `self.execute_payload` which applies changes to the `self.execution_state` -* a method `self.consensus_validated` which signals that the beacon block containing the execution payload +* a function `self.consensus_validated` which signals that the beacon block containing the execution payload is valid with respect to the consensus rule set +*Note*: `execute_payload` and `consensus_validated` are functions accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. + +The body of each of these functions is implementation dependent. +The Engine API may be used to implement them with an external execution engine. + #### `execute_payload` ```python @@ -262,11 +267,6 @@ def consensus_validated(self: ExecutionEngine, execution_payload: ExecutionPaylo ... ``` -The above functions are accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. - -The body of each of these functions is implementation dependent. -The Engine API may be used to implement them with an external execution engine. - ### Block processing *Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 15d47a650..5adeded16 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -31,11 +31,14 @@ This is the modification of the fork choice according to the executable beacon c ### `ExecutionEngine` -The following methods are added to the `ExecutionEngine` protocol for use in the fork choice: +*Note*: The `forkchoice_updated` function is added to the `ExecutionEngine` protocol to signal the fork choice updates. + +The body of this function is implementation dependent. +The Engine API may be used to implement it with an external execution engine. #### `forkchoice_updated` -This method performs two actions *atomically*: +This function performs two actions *atomically*: * Re-organizes the execution payload chain and corresponding state to make `head_block_hash` the head. * Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including `finalized_block_hash`. @@ -45,9 +48,6 @@ def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized ... ``` -The body of this function is implementation dependent. -The Engine API may be used to implement this with an external execution engine. - ## Helpers ### `PowBlock` diff --git a/specs/merge/validator.md b/specs/merge/validator.md index a84384dd6..aa5efc8ed 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -38,7 +38,10 @@ Please see related Beacon Chain doc before continuing and use them as a referenc ### `ExecutionEngine` -The following methods are added to the `ExecutionEngine` protocol for use as a validator: +*Note*: `prepare_payload` and `get_payload` functions are added to the `ExecutionEngine` protocol for use as a validator. + +The body of each of these functions is implementation dependent. +The Engine API may be used to implement them with an external execution engine. #### `prepare_payload` @@ -70,9 +73,6 @@ def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: ... ``` -The body of each of these functions is implementation dependent. -The Engine API may be used to implement them with an external execution engine. - ## Beacon chain responsibilities All validator responsibilities remain unchanged other than those noted below. Namely, the transition block handling and the addition of `ExecutionPayload`. @@ -134,4 +134,4 @@ def get_execution_payload(payload_id: Optional[uint64], execution_engine: Execut ``` *Note*: It is recommended for a validator to call `prepare_execution_payload` as soon as input parameters become known, -and make subsequent calls to this function if any of these parameters has been updated. +and make subsequent calls to this function when any of these parameters gets updated. From df01588464b2663bb0adf647c5f5e3a85283442c Mon Sep 17 00:00:00 2001 From: Anton Nashatyrev Date: Wed, 22 Sep 2021 18:40:10 +0300 Subject: [PATCH 23/41] Return back `proposer_index` validation for Gossip messages --- specs/sharding/p2p-interface.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/specs/sharding/p2p-interface.md b/specs/sharding/p2p-interface.md index 76a806635..ab32c37fa 100644 --- a/specs/sharding/p2p-interface.md +++ b/specs/sharding/p2p-interface.md @@ -97,6 +97,11 @@ on the horizontal subnet or creating samples for it. Alias `blob = signed_blob.m - _[REJECT]_ The blob builder defined by `blob.builder_index` exists and has sufficient balance to back the fee payment. - _[REJECT]_ The blob signature, `signed_blob.signature`, is valid for the aggregate of proposer and builder -- i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob.signature)`. +- _[REJECT]_ The blob is proposed by the expected `proposer_index` for the blob's `slot` and `shard`, + in the context of the current shuffling (defined by the current node head state and `blob.slot`). + If the `proposer_index` cannot immediately be verified against the expected shuffling, + the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- + in such a case _do not_ `REJECT`, instead `IGNORE` this message. #### Global topics @@ -127,6 +132,11 @@ The following validations MUST pass before forwarding the `signed_blob_header` o - _[REJECT]_ The blob builder defined by `blob.builder_index` exists and has sufficient balance to back the fee payment. - _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for the aggregate of proposer and builder -- i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob_header.signature)`. +- _[REJECT]_ The header is proposed by the expected `proposer_index` for the blob's `header.slot` and `header.shard` + in the context of the current shuffling (defined by the current node head state and `header.slot`). + If the `proposer_index` cannot immediately be verified against the expected shuffling, + the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- + in such a case _do not_ `REJECT`, instead `IGNORE` this message. ##### `shard_blob_tx` @@ -150,6 +160,11 @@ The following validations MUST pass before forwarding the `signed_blob_header` o Propagating nodes MAY increase fee increments in case of spam. - _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for ONLY the builder -- i.e. `bls.Verify(builder_pubkey, blob_signing_root, signed_blob_header.signature)`. The signature is not an aggregate with the proposer. +- _[REJECT]_ The header is designated for proposal by the expected `proposer_index` for the blob's `header.slot` and `header.shard` + in the context of the current shuffling (defined by the current node head state and `header.slot`). + If the `proposer_index` cannot immediately be verified against the expected shuffling, + the blob MAY be queued for later processing while proposers for the blob's branch are calculated -- + in such a case _do not_ `REJECT`, instead `IGNORE` this message. ##### `shard_proposer_slashing` From 24bacafeee3511b70741c7e7d4196856bcf9eb11 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 22 Sep 2021 23:52:15 +0600 Subject: [PATCH 24/41] Update consensus_validated description --- setup.py | 4 ++-- specs/merge/beacon-chain.md | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 1d647c2a1..6d75caeb1 100644 --- a/setup.py +++ b/setup.py @@ -522,10 +522,10 @@ def get_pow_chain_head() -> PowBlock: class NoopExecutionEngine(ExecutionEngine): - def execute_payload(self, execution_payload: ExecutionPayload) -> bool: + def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: return True - def consensus_validated(self: ExecutionEngine, execution_payload: ExecutionPayload) -> None: + def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: pass def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a1ab61848..eccb7f047 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -263,10 +263,15 @@ def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) #### `consensus_validated` ```python -def consensus_validated(self: ExecutionEngine, execution_payload: ExecutionPayload) -> None: +def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: ... ``` +The call of this function depends on the result of the state transition and must be done when call to the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: + +* `True` if `state_transition` function call succeedes +* `False` if `state_transition` function call fails + ### Block processing *Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. @@ -280,9 +285,6 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) - if is_execution_enabled(state, block.body): - # Notify the block is valid with respect to the consensus state transition function - EXECUTION_ENGINE.consensus_validated(block.body.execution_payload) # [New in Merge] ``` ### Execution payload processing From 38a4fd907e941d8aabb17fdc3090eb39002c33d6 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 22 Sep 2021 23:56:10 +0600 Subject: [PATCH 25/41] Fix spelling Co-authored-by: Hsiao-Wei Wang --- specs/merge/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index aa5efc8ed..115b992b0 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -68,7 +68,7 @@ has been built since the corresponding call to `prepare_payload` method. ```python def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: """ - Returns ``execution_payload`` object. + Return ``execution_payload`` object. """ ... ``` From f4bd37a10859206d47a1dd0754e4da8067d72544 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 22 Sep 2021 23:58:04 +0600 Subject: [PATCH 26/41] Fix spelling 2 --- specs/merge/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index eccb7f047..a99036fe5 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -269,7 +269,7 @@ def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) The call of this function depends on the result of the state transition and must be done when call to the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: -* `True` if `state_transition` function call succeedes +* `True` if `state_transition` function call succeeds * `False` if `state_transition` function call fails ### Block processing From eada985e9e10c40da7cd9bf773920d0ab93aac7e Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 13:16:18 +0600 Subject: [PATCH 27/41] Better wording for consensus_validated Co-authored-by: Danny Ryan --- specs/merge/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index a99036fe5..4a1c9c42f 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -267,7 +267,7 @@ def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) ... ``` -The call of this function depends on the result of the state transition and must be done when call to the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: +The inputs to this function depend on the result of the state transition. A call to `consensus_validated` must be made after the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: * `True` if `state_transition` function call succeeds * `False` if `state_transition` function call fails From c815f695cd01dbdfe79d80d06bb7570fa38bf7db Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 13:17:55 +0600 Subject: [PATCH 28/41] Polish comment in get_payload body Co-authored-by: Hsiao-Wei Wang --- specs/merge/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 115b992b0..4500d610c 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -55,7 +55,7 @@ def prepare_payload(self: ExecutionEngine, random: Bytes32, fee_recipient: Bytes20) -> uint64: """ - Returns ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call. + Return ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call. """ ... ``` From 7ef938da772886c31cb655e4b4fbd989188a2afb Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 13:37:52 +0600 Subject: [PATCH 29/41] Add notify_ prefix to EE functions sending notifications --- setup.py | 4 ++-- specs/merge/beacon-chain.md | 12 ++++++------ specs/merge/fork-choice.md | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 6d75caeb1..39eccad53 100644 --- a/setup.py +++ b/setup.py @@ -525,10 +525,10 @@ class NoopExecutionEngine(ExecutionEngine): def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: return True - def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: + def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: pass - def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: + def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: pass def prepare_payload(self: ExecutionEngine, diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 4a1c9c42f..9be89fcea 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -32,7 +32,7 @@ - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Execution engine](#execution-engine) - [`execute_payload`](#execute_payload) - - [`consensus_validated`](#consensus_validated) + - [`notify_consensus_validated`](#notify_consensus_validated) - [Block processing](#block-processing) - [Execution payload processing](#execution-payload-processing) - [`is_valid_gas_limit`](#is_valid_gas_limit) @@ -242,10 +242,10 @@ The implementation-dependent `ExecutionEngine` protocol encapsulates the executi * a state object `self.execution_state` of type `ExecutionState` * a state transition function `self.execute_payload` which applies changes to the `self.execution_state` -* a function `self.consensus_validated` which signals that the beacon block containing the execution payload +* a function `self.notify_consensus_validated` which signals that the beacon block containing the execution payload is valid with respect to the consensus rule set -*Note*: `execute_payload` and `consensus_validated` are functions accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. +*Note*: `execute_payload` and `notify_consensus_validated` are functions accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol. The body of each of these functions is implementation dependent. The Engine API may be used to implement them with an external execution engine. @@ -260,14 +260,14 @@ def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) ... ``` -#### `consensus_validated` +#### `notify_consensus_validated` ```python -def consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: +def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None: ... ``` -The inputs to this function depend on the result of the state transition. A call to `consensus_validated` must be made after the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: +The inputs to this function depend on the result of the state transition. A call to `notify_consensus_validated` must be made after the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows: * `True` if `state_transition` function call succeeds * `False` if `state_transition` function call fails diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 5adeded16..7b8643e99 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -10,7 +10,7 @@ - [Introduction](#introduction) - [Protocols](#protocols) - [`ExecutionEngine`](#executionengine) - - [`forkchoice_updated`](#forkchoice_updated) + - [`notify_forkchoice_updated`](#notify_forkchoice_updated) - [Helpers](#helpers) - [`PowBlock`](#powblock) - [`get_pow_block`](#get_pow_block) @@ -31,12 +31,12 @@ This is the modification of the fork choice according to the executable beacon c ### `ExecutionEngine` -*Note*: The `forkchoice_updated` function is added to the `ExecutionEngine` protocol to signal the fork choice updates. +*Note*: The `notify_forkchoice_updated` function is added to the `ExecutionEngine` protocol to signal the fork choice updates. The body of this function is implementation dependent. The Engine API may be used to implement it with an external execution engine. -#### `forkchoice_updated` +#### `notify_forkchoice_updated` This function performs two actions *atomically*: * Re-organizes the execution payload chain and corresponding state to make `head_block_hash` the head. @@ -44,7 +44,7 @@ This function performs two actions *atomically*: and corresponding state, up to and including `finalized_block_hash`. ```python -def forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: +def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None: ... ``` From b7deef16293916a0fa03c00544aac0b5ea43540d Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 13:50:46 +0600 Subject: [PATCH 30/41] Clarity which state should be used in prepare_payload in a better way --- specs/merge/validator.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 4500d610c..dc67997c7 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -83,10 +83,10 @@ All validator responsibilities remain unchanged other than those noted below. Na ##### ExecutionPayload -To obtain an execution payload, the proposer of a block must take the following actions: +To obtain an execution payload, a block proposer bulding a block on top of a `state` must take the following actions: 1. Set `payload_id = prepare_execution_payload(state, pow_chain, fee_recipient, execution_engine)`, where: - * `state` is the state for which `is_proposer(state, validator_index)` returns `True` + * `state` is the state object after applying `process_slots(state, slot)` transition to the resulting state of the parent block processing * `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 From 7d577ed422e7504238e7451247806aa1f3e960f7 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 14:35:55 +0600 Subject: [PATCH 31/41] Introduce ExecutionAddress type --- setup.py | 2 +- specs/merge/beacon-chain.md | 5 +++-- specs/merge/validator.md | 4 ++-- tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 39eccad53..efd4c29d5 100644 --- a/setup.py +++ b/setup.py @@ -535,7 +535,7 @@ class NoopExecutionEngine(ExecutionEngine): parent_hash: Hash32, timestamp: uint64, random: Bytes32, - feeRecipient: Bytes20) -> uint64: + feeRecipient: ExecutionAddress) -> uint64: raise NotImplementedError("no default block production") def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 9be89fcea..1be41a81e 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -54,6 +54,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f | - | - | - | | `OpaqueTransaction` | `ByteList[MAX_BYTES_PER_OPAQUE_TRANSACTION]` | a [typed transaction envelope](https://eips.ethereum.org/EIPS/eip-2718#opaque-byte-array-rather-than-an-rlp-array) structured as `TransactionType \|\| TransactionPayload` | | `Transaction` | `Union[OpaqueTransaction]` | a transaction | +| `ExecutionAddress` | `Bytes20` | Address of account on the execution layer | ## Constants @@ -159,7 +160,7 @@ class BeaconState(Container): class ExecutionPayload(Container): # Execution block header fields parent_hash: Hash32 - coinbase: Bytes20 # 'beneficiary' in the yellow paper + coinbase: ExecutionAddress # 'beneficiary' in the yellow paper state_root: Bytes32 receipt_root: Bytes32 # 'receipts root' in the yellow paper logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] @@ -181,7 +182,7 @@ class ExecutionPayload(Container): class ExecutionPayloadHeader(Container): # Execution block header fields parent_hash: Hash32 - coinbase: Bytes20 + coinbase: ExecutionAddress state_root: Bytes32 receipt_root: Bytes32 logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] diff --git a/specs/merge/validator.md b/specs/merge/validator.md index dc67997c7..e175a083e 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -53,7 +53,7 @@ def prepare_payload(self: ExecutionEngine, parent_hash: Hash32, timestamp: uint64, random: Bytes32, - fee_recipient: Bytes20) -> uint64: + fee_recipient: ExecutionAddress) -> uint64: """ Return ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call. """ @@ -103,7 +103,7 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ def prepare_execution_payload(state: BeaconState, pow_chain: Sequence[PowBlock], - fee_recipient: Bytes20, + fee_recipient: ExecutionAddress, execution_engine: ExecutionEngine) -> Optional[uint64]: if not is_merge_complete(state): terminal_pow_block = get_pow_block_at_total_difficulty(TERMINAL_TOTAL_DIFFICULTY, pow_chain) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 6126346a9..0d03447a7 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -11,7 +11,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None): payload = spec.ExecutionPayload( parent_hash=latest.block_hash, - coinbase=spec.Bytes20(), + coinbase=spec.ExecutionAddress(), state_root=latest.state_root, # no changes to the state receipt_root=b"no receipts here" + b"\x00" * 16, # TODO: root of empty MPT may be better. logs_bloom=spec.ByteVector[spec.BYTES_PER_LOGS_BLOOM](), # TODO: zeroed logs bloom for empty logs ok? From 41e06aec1bb093663c9bf28268deacfbce59e899 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 15:03:43 +0600 Subject: [PATCH 32/41] Introduce PayloadId type --- setup.py | 4 ++-- specs/merge/validator.md | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index efd4c29d5..9c1846737 100644 --- a/setup.py +++ b/setup.py @@ -535,10 +535,10 @@ class NoopExecutionEngine(ExecutionEngine): parent_hash: Hash32, timestamp: uint64, random: Bytes32, - feeRecipient: ExecutionAddress) -> uint64: + feeRecipient: ExecutionAddress) -> PayloadId: raise NotImplementedError("no default block production") - def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: + def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload: raise NotImplementedError("no default block production") diff --git a/specs/merge/validator.md b/specs/merge/validator.md index e175a083e..54ecbb64a 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -10,6 +10,7 @@ - [Introduction](#introduction) - [Prerequisites](#prerequisites) +- [Custom types](#custom-types) - [Protocols](#protocols) - [`ExecutionEngine`](#executionengine) - [`prepare_payload`](#prepare_payload) @@ -34,6 +35,12 @@ All behaviors and definitions defined in this document, and documents it extends 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. +## Custom types + +| Name | SSZ equivalent | Description | +| - | - | - | +| `PayloadId` | `uint64` | Identifier of a payload building process | + ## Protocols ### `ExecutionEngine` @@ -53,7 +60,7 @@ def prepare_payload(self: ExecutionEngine, parent_hash: Hash32, timestamp: uint64, random: Bytes32, - fee_recipient: ExecutionAddress) -> uint64: + fee_recipient: ExecutionAddress) -> PayloadId: """ Return ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call. """ @@ -66,7 +73,7 @@ Given the `payload_id`, `get_payload` returns the most recent version of the exe has been built since the corresponding call to `prepare_payload` method. ```python -def get_payload(self: ExecutionEngine, payload_id: uint64) -> ExecutionPayload: +def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload: """ Return ``execution_payload`` object. """ @@ -104,7 +111,7 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ def prepare_execution_payload(state: BeaconState, pow_chain: Sequence[PowBlock], fee_recipient: ExecutionAddress, - execution_engine: ExecutionEngine) -> Optional[uint64]: + 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) if terminal_pow_block is None: @@ -125,7 +132,7 @@ def prepare_execution_payload(state: BeaconState, 2. Set `block.body.execution_payload = get_execution_payload(payload_id, execution_engine)`, where: ```python -def get_execution_payload(payload_id: Optional[uint64], execution_engine: ExecutionEngine) -> ExecutionPayload: +def get_execution_payload(payload_id: Optional[PayloadId], execution_engine: ExecutionEngine) -> ExecutionPayload: if payload_id is None: # Pre-merge, empty payload return ExecutionPayload() From 0e2eb506751c99e82f4e004d2a95aa5a41020c8c Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 23 Sep 2021 15:30:14 +0600 Subject: [PATCH 33/41] Fix spelling --- specs/merge/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/validator.md b/specs/merge/validator.md index 54ecbb64a..1bc36b02d 100644 --- a/specs/merge/validator.md +++ b/specs/merge/validator.md @@ -90,7 +90,7 @@ All validator responsibilities remain unchanged other than those noted below. Na ##### ExecutionPayload -To obtain an execution payload, a block proposer bulding a block on top of a `state` must take the following actions: +To obtain an execution payload, a block proposer building a block on top of a `state` must take the following actions: 1. Set `payload_id = prepare_execution_payload(state, pow_chain, fee_recipient, execution_engine)`, where: * `state` is the state object after applying `process_slots(state, slot)` transition to the resulting state of the parent block processing From 0c65f79d824065606b5854002f37891f573b048e Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 23 Sep 2021 15:20:18 +0200 Subject: [PATCH 34/41] fix merkle proof test for mainnet The `test_next_sync_committee_tree` currently only supports the minimal preset, as it incorrectly initializes the `next_sync_committee`. On the mainnet preset, `SYNC_COMMITTEE_SIZE` is 512, but the default states use only 256 validators, leading to an IndexError during the test execution. `next_sync_committee` is already initialized correctly prior to the test run using the spec's `get_next_sync_committee` function, which fills up extra committee slots with duplicate validators in this scenario. This makes it unnecessary to manually initialize the `next_sync_committee`. Removed the incorrect initialization to allow testing on mainnet preset. --- .../core/pyspec/eth2spec/test/altair/unittests/test_helpers.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_helpers.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_helpers.py index c837f06c3..137539113 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_helpers.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_helpers.py @@ -9,9 +9,6 @@ from eth2spec.test.helpers.merkle import build_proof @with_phases([ALTAIR]) @spec_state_test def test_next_sync_committee_tree(spec, state): - state.next_sync_committee: object = spec.SyncCommittee( - pubkeys=[state.validators[i]for i in range(spec.SYNC_COMMITTEE_SIZE)] - ) next_sync_committee_branch = build_proof(state.get_backing(), spec.NEXT_SYNC_COMMITTEE_INDEX) assert spec.is_valid_merkle_branch( leaf=state.next_sync_committee.hash_tree_root(), From 08ca12ba970eece4d98d02a5ee55ae6efb555960 Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Thu, 23 Sep 2021 13:16:57 -0500 Subject: [PATCH 35/41] Fixed Altair p2p-interface.md Link --- specs/merge/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/p2p-interface.md b/specs/merge/p2p-interface.md index 85a96c31e..3febe9712 100644 --- a/specs/merge/p2p-interface.md +++ b/specs/merge/p2p-interface.md @@ -89,7 +89,7 @@ Alias `block = signed_beacon_block.message`, `execution_payload = block.body.exe ### Transitioning the gossip -See gossip transition details found in the [Altair document](../altair/p2p) for +See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for details on how to handle transitioning gossip topics for the Merge. ## The Req/Resp domain From d9a183b5cb049f4f0bce966365d40533d1403851 Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Thu, 23 Sep 2021 13:30:43 -0500 Subject: [PATCH 36/41] Modify Merge Gossip Block Validation Conditions --- specs/merge/p2p-interface.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specs/merge/p2p-interface.md b/specs/merge/p2p-interface.md index 85a96c31e..73bacbdde 100644 --- a/specs/merge/p2p-interface.md +++ b/specs/merge/p2p-interface.md @@ -68,12 +68,10 @@ See the Merge [state transition document](./beacon-chain.md#beaconblockbody) for In addition to the gossip validations for this topic from prior specifications, the following validations MUST pass before forwarding the `signed_beacon_block` on the network. Alias `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`. -- If the merge is complete with respect to the head state -- i.e. `is_merge_complete(state)` -- +- If the execution is enabled for the block or the block state -- i.e. `is_execution_enabled(state, block.body)` then validate the following: - _[REJECT]_ The block's execution payload must be non-empty -- i.e. `execution_payload != ExecutionPayload()` -- If the execution is enabled for the block -- i.e. `is_execution_enabled(state, block.body)` - then validate the following: - _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot -- i.e. `execution_payload.timestamp == compute_time_at_slot(state, block.slot)`. - _[REJECT]_ Gas used is less than the gas limit -- From 11840ce51ff69614d19747e546e8c1fa351a1a37 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 24 Sep 2021 16:31:09 +0600 Subject: [PATCH 37/41] Map EE calls on the PoS events defined in EIP-3675 --- specs/merge/beacon-chain.md | 2 ++ specs/merge/fork-choice.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 1be41a81e..053c829f1 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -273,6 +273,8 @@ The inputs to this function depend on the result of the state transition. A call * `True` if `state_transition` function call succeeds * `False` if `state_transition` function call fails +*Note*: The call of the `notify_consensus_validated` function with `valid = True` maps on the `POS_CONSENSUS_VALIDATED` event defined in the [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#definitions). + ### Block processing *Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block. diff --git a/specs/merge/fork-choice.md b/specs/merge/fork-choice.md index 7b8643e99..4cf413b10 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -48,6 +48,8 @@ def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, fi ... ``` +*Note*: The call of the `notify_forkchoice_updated` function maps on the `POS_FORKCHOICE_UPDATED` event defined in the [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#definitions). + ## Helpers ### `PowBlock` From e0eec44e34184ddcd371d4b15a9d591e015e869d Mon Sep 17 00:00:00 2001 From: Fredrik Svantes Date: Fri, 24 Sep 2021 12:45:37 +0200 Subject: [PATCH 38/41] No longer importing "Paragraph" removed Paragraph from being imported from marko.ext.gfm.elements as it is not being used --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6e55cfdde..d509e8779 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ except ImportError: from marko.block import Heading, FencedCode, LinkRefDef, BlankLine from marko.inline import CodeSpan from marko.ext.gfm import gfm -from marko.ext.gfm.elements import Table, Paragraph +from marko.ext.gfm.elements import Table # Definitions in context.py From d7665681a2bffb0e6405fa48f21b28342eff0fea Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 24 Sep 2021 06:08:01 -0600 Subject: [PATCH 39/41] simplify merge block gossip conditions --- specs/merge/p2p-interface.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specs/merge/p2p-interface.md b/specs/merge/p2p-interface.md index 73bacbdde..487b8f864 100644 --- a/specs/merge/p2p-interface.md +++ b/specs/merge/p2p-interface.md @@ -68,10 +68,8 @@ See the Merge [state transition document](./beacon-chain.md#beaconblockbody) for In addition to the gossip validations for this topic from prior specifications, the following validations MUST pass before forwarding the `signed_beacon_block` on the network. Alias `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`. -- If the execution is enabled for the block or the block state -- i.e. `is_execution_enabled(state, block.body)` +- If the execution is enabled for the block -- i.e. `is_execution_enabled(state, block.body)` then validate the following: - - _[REJECT]_ The block's execution payload must be non-empty -- - i.e. `execution_payload != ExecutionPayload()` - _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot -- i.e. `execution_payload.timestamp == compute_time_at_slot(state, block.slot)`. - _[REJECT]_ Gas used is less than the gas limit -- From 8d5106808fbb1c0a8d748625ef683e1e0707ced0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 24 Sep 2021 12:26:40 -0600 Subject: [PATCH 40/41] bump version to v1.1.0-beta.5 --- tests/core/pyspec/eth2spec/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index 3bec004b5..fbbb0af4d 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.1.0-beta.4 \ No newline at end of file +1.1.0-beta.5 \ No newline at end of file From 8a76a4143dfd7d58f8d48a289d9e270e7fc1eadb Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Fri, 24 Sep 2021 14:15:42 -0500 Subject: [PATCH 41/41] Fixed Validation Conditions (Function Renamed) --- specs/merge/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/merge/p2p-interface.md b/specs/merge/p2p-interface.md index e101c8ff3..954c1b008 100644 --- a/specs/merge/p2p-interface.md +++ b/specs/merge/p2p-interface.md @@ -71,7 +71,7 @@ Alias `block = signed_beacon_block.message`, `execution_payload = block.body.exe - If the execution is enabled for the block -- i.e. `is_execution_enabled(state, block.body)` then validate the following: - _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot - -- i.e. `execution_payload.timestamp == compute_time_at_slot(state, block.slot)`. + -- i.e. `execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot)`. - _[REJECT]_ Gas used is less than the gas limit -- i.e. `execution_payload.gas_used <= execution_payload.gas_limit`. - _[REJECT]_ The execution payload block hash is not equal to the parent hash --