diff --git a/setup.py b/setup.py index 8c2ec072df..205e8c400f 100644 --- a/setup.py +++ b/setup.py @@ -618,14 +618,14 @@ def imports(cls, preset_name: str): # # EIP4844SpecBuilder # -class EIP4844SpecBuilder(BellatrixSpecBuilder): +class EIP4844SpecBuilder(CapellaSpecBuilder): fork: str = EIP4844 @classmethod def imports(cls, preset_name: str): return super().imports(preset_name) + f''' from eth2spec.utils import kzg -from eth2spec.bellatrix import {preset_name} as bellatrix +from eth2spec.capella import {preset_name} as capella ''' @@ -652,6 +652,32 @@ def sundry_functions(cls) -> str: ROOTS_OF_UNITY = kzg.compute_roots_of_unity(TESTING_FIELD_ELEMENTS_PER_BLOB) +# +# Temporarily disable Withdrawals functions for EIP4844 testnets +# + + +def no_op(fn): # type: ignore + def wrapper(*args, **kw): # type: ignore + return None + return wrapper + + +def get_empty_list_result(fn): # type: ignore + def wrapper(*args, **kw): # type: ignore + return [] + return wrapper + + +process_withdrawals = no_op(process_withdrawals) +process_bls_to_execution_change = no_op(process_bls_to_execution_change) +get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals) + + +# +# End +# + def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> Optional[BlobsSidecar]: return "TEST"''' @@ -1002,7 +1028,7 @@ def finalize_options(self): specs/bellatrix/p2p-interface.md sync/optimistic.md """ - if self.spec_fork == CAPELLA: + if self.spec_fork in (CAPELLA, EIP4844): self.md_doc_paths += """ specs/capella/beacon-chain.md specs/capella/fork.md diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index d7d19b6137..4a6d4203b4 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -33,13 +33,14 @@ - [`process_execution_payload`](#process_execution_payload) - [Blob KZG commitments](#blob-kzg-commitments) - [Testing](#testing) + - [Disabling Withdrawals](#disabling-withdrawals) ## Introduction -This upgrade adds blobs to the beacon chain as part of EIP-4844. +This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an extension of the Capella upgrade. ## Custom types @@ -89,6 +90,7 @@ class BeaconBlockBody(Container): sync_aggregate: SyncAggregate # Execution execution_payload: ExecutionPayload + bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] ``` @@ -109,10 +111,11 @@ class ExecutionPayload(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_blobs: uint64 # [New in EIP-4844] + excess_data_gas: uint256 # [New in EIP-4844] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] ``` #### `ExecutionPayloadHeader` @@ -132,10 +135,11 @@ class ExecutionPayloadHeader(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_blobs: uint64 # [New in EIP-4844] + excess_data_gas: uint256 # [New in EIP-4844] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root + withdrawals_root: Root ``` ## Helper functions @@ -227,7 +231,8 @@ def verify_kzg_commitments_against_transactions(transactions: Sequence[Transacti 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) + process_withdrawals(state, block.body.execution_payload) + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP-4844] process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) @@ -253,6 +258,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify the execution payload is valid assert execution_engine.notify_new_payload(payload) + # Cache execution payload header state.latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, @@ -267,9 +273,10 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe timestamp=payload.timestamp, extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, - excess_blobs=payload.excess_blobs, # [New in EIP-4844] + excess_data_gas=payload.excess_data_gas, # [New in EIP-4844] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), + withdrawals_root=hash_tree_root(payload.withdrawals), ) ``` @@ -335,3 +342,10 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, return state ``` + +### Disabling Withdrawals +During testing we avoid Capella-specific updates to the state transition. We do this by replacing the following functions with a no-op implementation: +- `process_withdrawals` +- `process_bls_to_execution_change` + +The `get_expected_withdrawals` function is also modified to return an empty withdrawals list. As such, the PayloadAttributes used to update forkchoice does not contain withdrawals. diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index 8e3a727df3..ea5187c413 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -44,6 +44,8 @@ def compute_fork_version(epoch: Epoch) -> Version: """ if epoch >= EIP4844_FORK_EPOCH: return EIP4844_FORK_VERSION + if epoch >= CAPELLA_FORK_EPOCH: + return CAPELLA_FORK_VERSION if epoch >= BELLATRIX_FORK_EPOCH: return BELLATRIX_FORK_VERSION if epoch >= ALTAIR_FORK_EPOCH: @@ -62,12 +64,11 @@ Note that for the pure EIP-4844 networks, we don't apply `upgrade_to_eip4844` si ### Upgrading the state -Since the `eip4844.BeaconState` format is equal to the `bellatrix.BeaconState` format, we only have to update `BeaconState.fork`. +Since the `eip4844.BeaconState` format is equal to the `capella.BeaconState` format, we only have to update `BeaconState.fork`. ```python -def upgrade_to_eip4844(pre: bellatrix.BeaconState) -> BeaconState: - # TODO: if Capella gets scheduled, add sync it with Capella.BeaconState - epoch = bellatrix.get_current_epoch(pre) +def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: + epoch = capella.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=pre.latest_execution_payload_header.parent_hash, fee_recipient=pre.latest_execution_payload_header.fee_recipient, @@ -81,7 +82,7 @@ def upgrade_to_eip4844(pre: bellatrix.BeaconState) -> BeaconState: timestamp=pre.latest_execution_payload_header.timestamp, extra_data=pre.latest_execution_payload_header.extra_data, base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, - excess_data_gas=uint256(0), # [New in EIP-4844] + excess_data_gas=uint256(0), # [New in EIP-4844] block_hash=pre.latest_execution_payload_header.block_hash, transactions_root=pre.latest_execution_payload_header.transactions_root, withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, @@ -126,7 +127,10 @@ def upgrade_to_eip4844(pre: bellatrix.BeaconState) -> BeaconState: current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, # Execution-layer - latest_execution_payload_header=latest_execution_payload_header, + latest_execution_payload_header=latest_execution_payload_header, # [Modified in EIP4844] + # Withdrawals + next_withdrawal_index=pre.next_withdrawal_index, + next_withdrawal_validator_index=pre.next_withdrawal_validator_index, ) return post diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 953aad523f..6bdd619695 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -67,7 +67,7 @@ Some gossip meshes are upgraded in the fork of EIP4844 to support upgraded types Topics follow the same specification as in prior upgrades. All topics remain stable except the beacon block topic which is updated with the modified type. -The specification around the creation, validation, and dissemination of messages has not changed from the Bellatrix document unless explicitly noted here. +The specification around the creation, validation, and dissemination of messages has not changed from the Capella document unless explicitly noted here. The derivation of the `message-id` remains stable. @@ -124,6 +124,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | | `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | | `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | #### BeaconBlocksByRoot v2 @@ -142,6 +143,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | | `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | #### BeaconBlockAndBlobsSidecarByRoot v1 diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index d03b1842bb..57a5610ce4 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -29,7 +29,7 @@ This document represents the changes to be made in the code of an "honest valida ## Prerequisites -This document is an extension of the [Bellatrix -- Honest Validator](../bellatrix/validator.md) guide. +This document is an extension of the [Capella -- Honest Validator](../capella/validator.md) guide. All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of EIP4844](./beacon-chain.md) are requisite for this document and used throughout. @@ -60,7 +60,7 @@ Namely, the blob handling and the addition of `SignedBeaconBlockAndBlobsSidecar` ##### Blob KZG commitments -1. After retrieving the execution payload from the execution engine as specified in Bellatrix, +1. After retrieving the execution payload from the execution engine as specified in Capella, use the `payload_id` to retrieve `blobs` and `blob_kzg_commitments` via `get_blobs_and_kzg_commitments(payload_id)`. 2. Validate `blobs` and `blob_kzg_commitments`: diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 8ff02489cb..79d79fa6e4 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -1,7 +1,8 @@ +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_capella_and_later, always_bls +from eth2spec.test.context import spec_state_test, expect_assertion_error, with_phases, always_bls def run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=True): @@ -37,14 +38,14 @@ def run_bls_to_execution_change_processing(spec, state, signed_address_change, v yield 'post', state -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success(spec, state): signed_address_change = get_signed_address_change(spec, state) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_not_activated(spec, state): validator_index = 3 @@ -62,7 +63,7 @@ def test_success_not_activated(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_in_activation_queue(spec, state): validator_index = 3 @@ -80,7 +81,7 @@ def test_success_in_activation_queue(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_in_exit_queue(spec, state): validator_index = 3 @@ -93,7 +94,7 @@ def test_success_in_exit_queue(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_exited(spec, state): validator_index = 4 @@ -110,7 +111,7 @@ def test_success_exited(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_withdrawable(spec, state): validator_index = 4 @@ -128,7 +129,7 @@ def test_success_withdrawable(spec, state): assert spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_val_index_out_of_range(spec, state): # Create for one validator beyond the validator list length @@ -137,7 +138,7 @@ def test_fail_val_index_out_of_range(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_already_0x01(spec, state): # Create for one validator beyond the validator list length @@ -149,7 +150,7 @@ def test_fail_already_0x01(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_from_bls_pubkey(spec, state): # Create for one validator beyond the validator list length @@ -163,7 +164,7 @@ def test_fail_incorrect_from_bls_pubkey(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test @always_bls def test_fail_bad_signature(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py index e0603d301f..685d176518 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py @@ -1,7 +1,8 @@ from eth2spec.test.context import ( spec_state_test, - with_capella_and_later, + with_phases, ) +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.state import next_epoch_via_block from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -10,7 +11,7 @@ from eth2spec.test.helpers.withdrawals import set_validator_fully_withdrawable -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_top_up_to_withdrawn_validator(spec, state): validator_index = 0 diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py index 7b39f2b9dc..da3ddcb4d9 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py @@ -3,10 +3,10 @@ from eth2spec.test.context import ( spec_state_test, expect_assertion_error, - with_capella_and_later, with_presets, + with_phases, ) -from eth2spec.test.helpers.constants import MINIMAL +from eth2spec.test.helpers.constants import MINIMAL, CAPELLA from eth2spec.test.helpers.execution_payload import ( build_empty_execution_payload, ) @@ -87,7 +87,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with return expected_withdrawals -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_zero_expected_withdrawals(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 @@ -98,7 +98,7 @@ def test_success_zero_expected_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_full_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -115,7 +115,7 @@ def test_success_one_full_withdrawal(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -135,7 +135,7 @@ def test_success_one_partial_withdrawal(spec, state): ) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_max_per_slot(spec, state): num_full_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD // 2 @@ -153,7 +153,7 @@ def test_success_max_per_slot(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_all_fully_withdrawable(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -168,7 +168,7 @@ def test_success_all_fully_withdrawable(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_all_partially_withdrawable(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -187,7 +187,7 @@ def test_success_all_partially_withdrawable(spec, state): # Failure cases in which the number of withdrawals in the execution_payload is incorrect # -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_non_withdrawable_non_empty_withdrawals(spec, state): next_slot(spec, state) @@ -203,7 +203,7 @@ def test_fail_non_withdrawable_non_empty_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_one_expected_full_withdrawal_and_none_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -215,7 +215,7 @@ def test_fail_one_expected_full_withdrawal_and_none_in_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_one_expected_partial_withdrawal_and_none_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=1) @@ -227,7 +227,7 @@ def test_fail_one_expected_partial_withdrawal_and_none_in_withdrawals(spec, stat yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_one_expected_full_withdrawal_and_duplicate_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=2) @@ -239,7 +239,7 @@ def test_fail_one_expected_full_withdrawal_and_duplicate_in_withdrawals(spec, st yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_two_expected_partial_withdrawal_and_duplicate_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=2) @@ -251,7 +251,7 @@ def test_fail_two_expected_partial_withdrawal_and_duplicate_in_withdrawals(spec, yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_max_per_slot_full_withdrawals_and_one_less_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -263,7 +263,7 @@ def test_fail_max_per_slot_full_withdrawals_and_one_less_in_withdrawals(spec, st yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_max_per_slot_partial_withdrawals_and_one_less_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -275,7 +275,7 @@ def test_fail_max_per_slot_partial_withdrawals_and_one_less_in_withdrawals(spec, yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_a_lot_fully_withdrawable_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -287,7 +287,7 @@ def test_fail_a_lot_fully_withdrawable_too_few_in_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_a_lot_partially_withdrawable_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -299,7 +299,7 @@ def test_fail_a_lot_partially_withdrawable_too_few_in_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_a_lot_mixed_withdrawable_in_queue_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4, @@ -316,7 +316,7 @@ def test_fail_a_lot_mixed_withdrawable_in_queue_too_few_in_withdrawals(spec, sta # Failure cases in which the withdrawals in the execution_payload are incorrect # -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_withdrawal_index(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -328,7 +328,7 @@ def test_fail_incorrect_withdrawal_index(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_address_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -340,7 +340,7 @@ def test_fail_incorrect_address_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_address_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=1) @@ -352,7 +352,7 @@ def test_fail_incorrect_address_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_amount_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -364,7 +364,7 @@ def test_fail_incorrect_amount_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_incorrect_amount_partial(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -376,7 +376,7 @@ def test_fail_incorrect_amount_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_one_of_many_incorrectly_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -394,7 +394,7 @@ def test_fail_one_of_many_incorrectly_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_one_of_many_incorrectly_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -412,7 +412,7 @@ def test_fail_one_of_many_incorrectly_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_many_incorrectly_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -430,7 +430,7 @@ def test_fail_many_incorrectly_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_fail_many_incorrectly_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -452,7 +452,7 @@ def test_fail_many_incorrectly_partial(spec, state): # More full withdrawal cases # -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_withdrawable_epoch_but_0_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -466,7 +466,7 @@ def test_withdrawable_epoch_but_0_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_withdrawable_epoch_but_0_effective_balance_0_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -480,7 +480,7 @@ def test_withdrawable_epoch_but_0_effective_balance_0_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_withdrawable_epoch_but_0_effective_balance_nonzero_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -494,7 +494,7 @@ def test_withdrawable_epoch_but_0_effective_balance_nonzero_balance(spec, state) yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_no_withdrawals_but_some_next_epoch(spec, state): current_epoch = spec.get_current_epoch(state) @@ -508,7 +508,7 @@ def test_no_withdrawals_but_some_next_epoch(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_all_withdrawal(spec, state): # Make all validators withdrawable @@ -544,25 +544,25 @@ def run_random_full_withdrawals_test(spec, state, rng): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_full_withdrawals_0(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(444)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_full_withdrawals_1(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(420)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_full_withdrawals_2(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(200)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_full_withdrawals_3(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(2000000)) @@ -572,7 +572,7 @@ def test_random_full_withdrawals_3(spec, state): # More partial withdrawal cases # -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_no_max_effective_balance(spec, state): validator_index = len(state.validators) // 2 @@ -588,7 +588,7 @@ def test_success_no_max_effective_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_no_excess_balance(spec, state): validator_index = len(state.validators) // 2 @@ -604,7 +604,7 @@ def test_success_no_excess_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_excess_balance_but_no_max_effective_balance(spec, state): validator_index = len(state.validators) // 2 @@ -621,7 +621,7 @@ def test_success_excess_balance_but_no_max_effective_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable_not_yet_active(spec, state): validator_index = len(state.validators) // 2 @@ -635,7 +635,7 @@ def test_success_one_partial_withdrawable_not_yet_active(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable_in_exit_queue(spec, state): validator_index = len(state.validators) // 2 @@ -650,7 +650,7 @@ def test_success_one_partial_withdrawable_in_exit_queue(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable_exited(spec, state): validator_index = len(state.validators) // 2 @@ -664,7 +664,7 @@ def test_success_one_partial_withdrawable_exited(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable_active_and_slashed(spec, state): validator_index = len(state.validators) // 2 @@ -678,7 +678,7 @@ def test_success_one_partial_withdrawable_active_and_slashed(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable_exited_and_slashed(spec, state): validator_index = len(state.validators) // 2 @@ -693,7 +693,7 @@ def test_success_one_partial_withdrawable_exited_and_slashed(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_two_partial_withdrawable(spec, state): set_validator_partially_withdrawable(spec, state, 0) @@ -704,7 +704,7 @@ def test_success_two_partial_withdrawable(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=2) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_max_partial_withdrawable(spec, state): # Sanity check that this test works for this state @@ -719,7 +719,7 @@ def test_success_max_partial_withdrawable(spec, state): spec, state, execution_payload, num_expected_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) -@with_capella_and_later +@with_phases([CAPELLA]) @with_presets([MINIMAL], reason="not enough validators with mainnet config") @spec_state_test def test_success_max_plus_one_withdrawable(spec, state): @@ -758,37 +758,37 @@ def run_random_partial_withdrawals_test(spec, state, rng): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_0(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(0)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_partial_withdrawals_1(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(1)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_partial_withdrawals_2(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(2)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_partial_withdrawals_3(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(3)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_partial_withdrawals_4(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(4)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_partial_withdrawals_5(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(5)) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index f3ad843b11..3c406e524d 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -1,7 +1,7 @@ from eth2spec.test.context import ( - with_capella_and_later, spec_state_test + with_phases, spec_state_test ) - +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.state import ( state_transition_and_sign_block, ) @@ -21,7 +21,7 @@ from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_successful_bls_change(spec, state): index = 0 @@ -44,7 +44,7 @@ def test_successful_bls_change(spec, state): assert post_credentials[12:] == signed_address_change.message.to_execution_address -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_full_withdrawal_in_epoch_transition(spec, state): index = 0 @@ -65,7 +65,7 @@ def test_full_withdrawal_in_epoch_transition(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_partial_withdrawal_in_epoch_transition(spec, state): index = state.next_withdrawal_index @@ -89,7 +89,7 @@ def test_partial_withdrawal_in_epoch_transition(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_many_partial_withdrawals_in_epoch_transition(spec, state): assert len(state.validators) > spec.MAX_WITHDRAWALS_PER_PAYLOAD @@ -112,7 +112,7 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state): assert len(spec.get_expected_withdrawals(state)) == 1 -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_exit_and_bls_change(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit @@ -170,7 +170,7 @@ def _perform_valid_withdrawal(spec, state): return pre_state, signed_block_1, pre_next_withdrawal_index -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_withdrawal_success_two_blocks(spec, state): pre_state, signed_block_1, pre_next_withdrawal_index = _perform_valid_withdrawal(spec, state) @@ -187,7 +187,7 @@ def test_withdrawal_success_two_blocks(spec, state): yield 'post', state -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_withdrawal_fail_second_block_payload_isnt_compatible(spec, state): _perform_valid_withdrawal(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index f8bbdf5ba4..94910fa473 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -306,6 +306,7 @@ def config_fork_epoch_overrides(spec, state): elif _check_current_version(spec, state, EIP4844): overrides['ALTAIR_FORK_EPOCH'] = spec.GENESIS_EPOCH overrides['BELLATRIX_FORK_EPOCH'] = spec.GENESIS_EPOCH + overrides['CAPELLA_FORK_EPOCH'] = spec.GENESIS_EPOCH overrides['EIP4844_FORK_EPOCH'] = spec.GENESIS_EPOCH elif _check_current_version(spec, state, SHARDING): overrides['ALTAIR_FORK_EPOCH'] = spec.GENESIS_EPOCH diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py new file mode 100644 index 0000000000..d9b93394f6 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py @@ -0,0 +1,40 @@ +from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change +from eth2spec.test.context import spec_state_test, expect_assertion_error, with_eip4844_and_later + + +def run_bls_to_execution_change_processing_no_op(spec, state, signed_address_change, valid=True): + """ + Run ``process_bls_to_execution_change``, yielding: + - pre-state ('pre') + - address-change ('address_change') + - post-state ('post'). + If ``valid == False``, run expecting ``AssertionError`` + """ + pre_state = state.copy() + + # yield pre-state + yield 'pre', state + + yield 'address_change', signed_address_change + + # If the address_change is invalid, processing is aborted, and there is no post-state. + if not valid: + expect_assertion_error(lambda: spec.process_bls_to_execution_change(state, signed_address_change)) + yield 'post', None + return + + # process address change + spec.process_bls_to_execution_change(state, signed_address_change) + + # yield post-state + yield 'post', state + + # Make sure state has NOT been changed + assert state == pre_state + + +@with_eip4844_and_later +@spec_state_test +def test_no_op(spec, state): + signed_address_change = get_signed_address_change(spec, state) + yield from run_bls_to_execution_change_processing_no_op(spec, state, signed_address_change) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py new file mode 100644 index 0000000000..a7db37e422 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py @@ -0,0 +1,41 @@ + +from eth2spec.test.context import spec_state_test, expect_assertion_error, with_eip4844_and_later +from eth2spec.test.helpers.execution_payload import ( + build_empty_execution_payload, +) +from eth2spec.test.helpers.state import next_slot + + +def run_withdrawals_processing(spec, state, execution_payload, valid=True): + """ + Run ``process_execution_payload``, yielding: + - pre-state ('pre') + - execution payload ('execution_payload') + - post-state ('post'). + If ``valid == False``, run expecting ``AssertionError`` + """ + pre_state = state.copy() + + yield 'pre', state + yield 'execution_payload', execution_payload + + if not valid: + expect_assertion_error(lambda: spec.process_withdrawals(state, execution_payload)) + yield 'post', None + return + + spec.process_withdrawals(state, execution_payload) + + yield 'post', state + + # Make sure state has NOT been changed + assert state == pre_state + + +@with_eip4844_and_later +@spec_state_test +def test_no_op(spec, state): + next_slot(spec, state) + execution_payload = build_empty_execution_payload(spec, state) + + yield from run_withdrawals_processing(spec, state, execution_payload) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 598b189efc..b67b11f10c 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -32,6 +32,7 @@ PHASE0: ALTAIR, ALTAIR: BELLATRIX, BELLATRIX: CAPELLA, + CAPELLA: EIP4844, } ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items() AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index d6d88876ad..82ff12ff1d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -5,7 +5,7 @@ def is_post_fork(a, b): if a == EIP4844: - return b in [PHASE0, ALTAIR, BELLATRIX, EIP4844] + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844] if a == CAPELLA: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA] if a == BELLATRIX: