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 $@ 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 diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index dd5b394af..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) @@ -31,9 +37,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..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] @@ -30,9 +36,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/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/beacon-chain.md b/specs/merge/beacon-chain.md index ed12d3eb6..39f457252 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 settings](#transition-settings) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) @@ -64,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 @@ -76,6 +78,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` | **TBD** | + ## Containers ### Extended containers @@ -159,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 @@ -180,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 @@ -246,15 +256,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 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: 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,16 +296,16 @@ 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 + # 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 @@ -310,6 +322,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/specs/merge/client-settings.md b/specs/merge/client-settings.md new file mode 100644 index 000000000..64b2b20e6 --- /dev/null +++ b/specs/merge/client-settings.md @@ -0,0 +1,21 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [The Merge -- Client Settings](#the-merge----client-settings) + - [Override terminal total difficulty](#override-terminal-total-difficulty) + + + +# The Merge -- Client Settings + +**Notice**: This document is a work-in-progress for researchers and implementers. + +This document specifies configurable settings that clients must implement for the Merge. + +### Override terminal total difficulty + +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. + +Except under exceptional scenarios, this setting is expected to not be used. Sufficient warning to the user about this exceptional configurable setting should be provided. + diff --git a/specs/merge/client_settings.md b/specs/merge/client_settings.md deleted file mode 100644 index a8ca633ff..000000000 --- a/specs/merge/client_settings.md +++ /dev/null @@ -1,26 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [The Merge -- Client Settings](#the-merge----client-settings) - - [Override terminal total difficulty](#override-terminal-total-difficulty) - - - -# The Merge -- Client Settings - -**Notice**: This document is a work-in-progress for researchers and implementers. - -This document specifies configurable settings that clients must implement for the Merge. - -### 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. - -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, 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 2e228a2e1..8051ab3eb 100644 --- a/specs/merge/fork-choice.md +++ b/specs/merge/fork-choice.md @@ -13,11 +13,9 @@ - [`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) - - [`process_merge_execution_payload`](#process_merge_execution_payload) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -69,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 @@ -84,8 +74,6 @@ class TransitionStore(object): class PowBlock(object): block_hash: Hash32 parent_hash: Hash32 - is_processed: boolean - is_valid: boolean total_difficulty: uint256 difficulty: uint256 ``` @@ -94,30 +82,17 @@ 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` 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 - return block.is_valid and is_total_difficulty_reached and is_parent_total_difficulty_valid -``` - -### `process_merge_execution_payload` - -Used by fork-choice handler, `on_block` to check validity of terminal block. - -```python -def process_merge_execution_payload(transition_store: TransitionStore, execution_payload: ExecutionPayload) -> None: - # Delay consideration of block until PoW block is processed by the PoW node - pow_block = get_pow_block(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) +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 ``` ## Updated fork-choice handlers @@ -127,7 +102,7 @@ def process_merge_execution_payload(transition_store: TransitionStore, execution *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 @@ -142,13 +117,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): - process_merge_execution_payload(transition_store, block.body.execution_payload) - # Check the block is valid and compute the post-state state = pre_state.copy() state_transition(state, signed_block, True) + + # [New in Merge] + 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(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 diff --git a/specs/merge/fork.md b/specs/merge/fork.md index be791afa9..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` | `uint256(2 ** 32)` **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 * uint256(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 efeeca061..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]: @@ -75,35 +75,27 @@ 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) 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): - 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() 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) ``` 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/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))] diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index 7daa51970..9e704cb49 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -100,8 +100,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 diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index d82a6a54d..453c49d3e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -23,6 +23,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, @@ -45,6 +46,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) 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 93cc925fb..8231c0223 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 @@ -148,6 +148,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): 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()