diff --git a/setup.py b/setup.py index 8c2ec072d..205e8c400 100644 --- a/setup.py +++ b/setup.py @@ -618,14 +618,14 @@ from eth2spec.bellatrix import {preset_name} as bellatrix # # 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 @@ KZG_SETUP_LAGRANGE = TESTING_KZG_SETUP_LAGRANGE 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 @@ class PySpecCommand(Command): 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 d7d19b613..4a6d4203b 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 8e3a727df..ea5187c41 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 aca38debe..57c695cef 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -133,6 +133,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 @@ -151,6 +152,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 d03b1842b..57a5610ce 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 8ff02489c..79d79fa6e 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 e0603d301..685d17651 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.deposits import ( 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 7b39f2b9d..da3ddcb4d 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 @@ import random 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 f3ad843b1..3c406e524 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.withdrawals import ( 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 f8bbdf5ba..94910fa47 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 000000000..e69de29bb 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 000000000..d9b93394f --- /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 000000000..a7db37e42 --- /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 598b189ef..b67b11f10 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -32,6 +32,7 @@ ALL_FORK_UPGRADES = { 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 d6d88876a..82ff12ff1 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -5,7 +5,7 @@ from .constants import ( 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: