From 242e1b73bb16e2cbad5b3947f63a7569c833c732 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 20 Oct 2022 10:30:49 -0400 Subject: [PATCH 01/20] Rebase Capella on EIP-4844 This also introduces an `ENABLE_WITHDRAWALS` feature-flag to allow implementers test EIP-4844 without including Capella-specific state changes. --- specs/eip4844/beacon-chain.md | 64 ++++++++++++++++++++++++++++++++-- specs/eip4844/fork.md | 13 ++++--- specs/eip4844/p2p-interface.md | 2 +- specs/eip4844/validator.md | 59 +++++++++++++++++++++++++++++-- 4 files changed, 128 insertions(+), 10 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 4cf9535933..877c3332aa 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -15,6 +15,7 @@ - [Domain types](#domain-types) - [Preset](#preset) - [Execution](#execution) + - [Test Parameters](#test-parameters) - [Configuration](#configuration) - [Containers](#containers) - [Extended containers](#extended-containers) @@ -27,9 +28,11 @@ - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions) - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Epoch processing](#epoch-processing) - [Block processing](#block-processing) - [Execution payload](#execution-payload) - [`process_execution_payload`](#process_execution_payload) + - [Modified `process_operations`](#modified-process_operations) - [Blob KZG commitments](#blob-kzg-commitments) - [Testing](#testing) @@ -38,7 +41,7 @@ ## 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. We introduce a new feature flag, `ENABLE_WITHDRAWALS`, to disable Capella-specific updates to the state transition function. This is done to minimize Capella specific issues that may arise during testing. `ENABLE_WITHDRAWALS` will be removed in the final upgrade specification. ## Custom types @@ -72,6 +75,10 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | - | - | | `MAX_BLOBS_PER_BLOCK` | `uint64(2**4)` (= 16) | +### Test Parameters +| Name | Value | +| `ENABLE_WITHDRAWALS` | `uint64(0)` | + ## Configuration @@ -97,6 +104,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] ``` @@ -121,6 +129,7 @@ class ExecutionPayload(Container): # 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` @@ -144,6 +153,7 @@ class ExecutionPayloadHeader(Container): # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root + withdrawals_root: Root ``` ## Helper functions @@ -192,13 +202,37 @@ def verify_kzg_commitments_against_transactions(transactions: Sequence[Transacti ## Beacon chain state transition function +### Epoch processing + +```python +def process_epoch(state: BeaconState) -> None: + process_justification_and_finalization(state) + process_inactivity_updates(state) + process_rewards_and_penalties(state) + process_registry_updates(state) + process_slashings(state) + process_eth1_data_reset(state) + process_effective_balance_updates(state) + process_slashings_reset(state) + process_randao_mixes_reset(state) + process_historical_roots_update(state) + process_participation_flag_updates(state) + process_sync_committee_updates(state) + if ENABLE_WITHDRAWALS: + process_full_withdrawals(state) + process_partial_withdrawals(state) +``` + + ### Block processing ```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) + if ENABLE_WITHDRAWALS: # [New in EIP-4844] + 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) @@ -221,6 +255,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, @@ -238,9 +273,32 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe excess_blobs=payload.excess_blobs, # [New in EIP-4844] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), - ) + withdrawals_root=hash_tree_root(payload.withdrawals) if ENABLE_WITHDRAWALS else Bytes32(), # [New in EIP-4844] ``` +#### Modified `process_operations` + +*Note*: The function `process_operations` is modified to feature flag Withdrawals. + +```python +def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: + # Verify that outstanding deposits are processed up to the maximum number of deposits + assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) + + def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: + for operation in operations: + fn(state, operation) + + for_ops(body.proposer_slashings, process_proposer_slashing) + for_ops(body.attester_slashings, process_attester_slashing) + for_ops(body.attestations, process_attestation) + for_ops(body.deposits, process_deposit) + for_ops(body.voluntary_exits, process_voluntary_exit) + if ENABLE_WITHDRAWALS: # [New in EIP-4844] + for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) +``` + + #### Blob KZG commitments ```python diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index eaabba916a..bce6ffe703 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) post = BeaconState( # Versioning genesis_time=pre.genesis_time, @@ -109,6 +110,10 @@ def upgrade_to_eip4844(pre: bellatrix.BeaconState) -> BeaconState: next_sync_committee=pre.next_sync_committee, # Execution-layer latest_execution_payload_header=pre.latest_execution_payload_header, + # Withdrawals + withdrawal_queue=[], + next_withdrawal_index=WithdrawalIndex(0), + next_partial_withdrawal_validator_index=ValidatorIndex(0), ) return post diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index eab8815a4a..60ccb07398 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. diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index e1bcf9564a..c998aeb6ef 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -15,6 +15,9 @@ - [`BlobsAndCommitments`](#blobsandcommitments) - [`PolynomialAndCommitment`](#polynomialandcommitment) - [Helpers](#helpers) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [`get_payload`](#get_payload) - [`is_data_available`](#is_data_available) - [`hash_to_bls_field`](#hash_to_bls_field) - [`compute_powers`](#compute_powers) @@ -27,6 +30,7 @@ - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [Blob KZG commitments](#blob-kzg-commitments) - [Beacon Block publishing time](#beacon-block-publishing-time) + - [ExecutionPayload](#executionpayload) @@ -37,7 +41,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. @@ -70,6 +74,14 @@ class PolynomialAndCommitment(Container): ## Helpers +## Protocols + +### `ExecutionEngine` + +#### `get_payload` + +`get_payload` returns the upgraded EIP-4844 `ExecutionPayload` type. + ### `is_data_available` The implementation of `is_data_available` is meant to change with later sharding upgrades. @@ -200,7 +212,7 @@ Namely, the blob handling and the addition of `BlobsSidecar`. ##### 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`: @@ -252,3 +264,46 @@ The validator MUST hold on to blobs for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` to ensure the data-availability of these blobs throughout the network. After `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` nodes MAY prune the blobs and/or stop serving them. + +##### ExecutionPayload + +`ExecutionPayload`s are constructed as they were in Capella, except that we allow withdrawals to be disabled for testing. + +```python +def prepare_execution_payload(state: BeaconState, + pow_chain: Dict[Hash32, PowBlock], + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + execution_engine: ExecutionEngine) -> Optional[PayloadId]: + if not is_merge_transition_complete(state): + is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32() + is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH + if is_terminal_block_hash_set and not is_activation_epoch_reached: + # Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed + return None + + terminal_pow_block = get_terminal_pow_block(pow_chain) + if terminal_pow_block is None: + # Pre-merge, no prepare payload call is needed + return None + # Signify merge via producing on top of the terminal PoW block + parent_hash = terminal_pow_block.block_hash + else: + # Post-merge, normal payload + parent_hash = state.latest_execution_payload_header.block_hash + + # Set the forkchoice head and initiate the payload build process + payload_attributes = PayloadAttributes( + timestamp=compute_timestamp_at_slot(state, state.slot), + prev_randao=get_randao_mix(state, get_current_epoch(state)), + suggested_fee_recipient=suggested_fee_recipient, + withdrawals=get_expected_withdrawals(state) if ENABLE_WITHDRAWALS else None, # [New in EIP-4844] + ) + return execution_engine.notify_forkchoice_updated( + head_block_hash=parent_hash, + safe_block_hash=safe_block_hash, + finalized_block_hash=finalized_block_hash, + payload_attributes=payload_attributes, + ) +``` From f6f2474c87edb910ec22710f7340a9dffc570e06 Mon Sep 17 00:00:00 2001 From: Inphi Date: Thu, 20 Oct 2022 14:39:18 -0400 Subject: [PATCH 02/20] Update specs/eip4844/beacon-chain.md Co-authored-by: Hsiao-Wei Wang --- specs/eip4844/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 877c3332aa..7e16bca2f2 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -274,6 +274,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals) if ENABLE_WITHDRAWALS else Bytes32(), # [New in EIP-4844] + ) ``` #### Modified `process_operations` From 2ac57c7e7b203cce45df6d284ca01b29a0b60f4b Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 24 Oct 2022 12:44:11 -0400 Subject: [PATCH 03/20] Fix py setup And remove the ENABLE_WITHDRAWALS feature-flag. The Testing section in the spec has been updated to specify how withdrawals is to be disabled --- setup.py | 6 ++--- specs/eip4844/beacon-chain.md | 30 +++++++++++++----------- specs/eip4844/fork.md | 2 +- specs/eip4844/validator.md | 44 ----------------------------------- 4 files changed, 20 insertions(+), 62 deletions(-) diff --git a/setup.py b/setup.py index 6db4aa8707..6a58e6ff18 100644 --- a/setup.py +++ b/setup.py @@ -582,14 +582,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 from eth2spec.utils.ssz.ssz_impl import serialize as ssz_serialize ''' @@ -967,7 +967,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 7e16bca2f2..e92f932d06 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -15,7 +15,6 @@ - [Domain types](#domain-types) - [Preset](#preset) - [Execution](#execution) - - [Test Parameters](#test-parameters) - [Configuration](#configuration) - [Containers](#containers) - [Extended containers](#extended-containers) @@ -35,13 +34,14 @@ - [Modified `process_operations`](#modified-process_operations) - [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 is an extension of the Capella upgrade. We introduce a new feature flag, `ENABLE_WITHDRAWALS`, to disable Capella-specific updates to the state transition function. This is done to minimize Capella specific issues that may arise during testing. `ENABLE_WITHDRAWALS` will be removed in the final upgrade specification. +This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an extension of the Capella upgrade. ## Custom types @@ -75,10 +75,6 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an exte | - | - | | `MAX_BLOBS_PER_BLOCK` | `uint64(2**4)` (= 16) | -### Test Parameters -| Name | Value | -| `ENABLE_WITHDRAWALS` | `uint64(0)` | - ## Configuration @@ -218,9 +214,8 @@ def process_epoch(state: BeaconState) -> None: process_historical_roots_update(state) process_participation_flag_updates(state) process_sync_committee_updates(state) - if ENABLE_WITHDRAWALS: - process_full_withdrawals(state) - process_partial_withdrawals(state) + process_full_withdrawals(state) + process_partial_withdrawals(state) ``` @@ -230,8 +225,7 @@ def process_epoch(state: BeaconState) -> None: def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) if is_execution_enabled(state, block.body): - if ENABLE_WITHDRAWALS: # [New in EIP-4844] - process_withdrawals(state, block.body.execution_payload) + 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) @@ -273,7 +267,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe excess_blobs=payload.excess_blobs, # [New in EIP-4844] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), - withdrawals_root=hash_tree_root(payload.withdrawals) if ENABLE_WITHDRAWALS else Bytes32(), # [New in EIP-4844] + withdrawals_root=hash_tree_root(payload.withdrawals), ) ``` @@ -295,8 +289,7 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.attestations, process_attestation) for_ops(body.deposits, process_deposit) for_ops(body.voluntary_exits, process_voluntary_exit) - if ENABLE_WITHDRAWALS: # [New in EIP-4844] - for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) + for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) ``` @@ -362,3 +355,12 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, return state ``` + +### Disabling Withdrawals +During testing we avoid Capella-specific updates the state transition. We do this by replacing the following functions with a no-op implementation: +- `process_full_withdrawals` +- `process_partial_withdrawals` +- `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 bce6ffe703..e404265572 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -67,7 +67,7 @@ Note that for the pure EIP-4844 networks, we don't apply `upgrade_to_eip4844` si 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: Capella.BeaconState) -> BeaconState: +def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: epoch = capella.get_current_epoch(pre) post = BeaconState( # Versioning diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index c998aeb6ef..41f5aab700 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -30,7 +30,6 @@ - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [Blob KZG commitments](#blob-kzg-commitments) - [Beacon Block publishing time](#beacon-block-publishing-time) - - [ExecutionPayload](#executionpayload) @@ -264,46 +263,3 @@ The validator MUST hold on to blobs for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` to ensure the data-availability of these blobs throughout the network. After `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` nodes MAY prune the blobs and/or stop serving them. - -##### ExecutionPayload - -`ExecutionPayload`s are constructed as they were in Capella, except that we allow withdrawals to be disabled for testing. - -```python -def prepare_execution_payload(state: BeaconState, - pow_chain: Dict[Hash32, PowBlock], - safe_block_hash: Hash32, - finalized_block_hash: Hash32, - suggested_fee_recipient: ExecutionAddress, - execution_engine: ExecutionEngine) -> Optional[PayloadId]: - if not is_merge_transition_complete(state): - is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32() - is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH - if is_terminal_block_hash_set and not is_activation_epoch_reached: - # Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed - return None - - terminal_pow_block = get_terminal_pow_block(pow_chain) - if terminal_pow_block is None: - # Pre-merge, no prepare payload call is needed - return None - # Signify merge via producing on top of the terminal PoW block - parent_hash = terminal_pow_block.block_hash - else: - # Post-merge, normal payload - parent_hash = state.latest_execution_payload_header.block_hash - - # Set the forkchoice head and initiate the payload build process - payload_attributes = PayloadAttributes( - timestamp=compute_timestamp_at_slot(state, state.slot), - prev_randao=get_randao_mix(state, get_current_epoch(state)), - suggested_fee_recipient=suggested_fee_recipient, - withdrawals=get_expected_withdrawals(state) if ENABLE_WITHDRAWALS else None, # [New in EIP-4844] - ) - return execution_engine.notify_forkchoice_updated( - head_block_hash=parent_hash, - safe_block_hash=safe_block_hash, - finalized_block_hash=finalized_block_hash, - payload_attributes=payload_attributes, - ) -``` From 0488c0c26e541db04a04f4bbc3b3d138a6b62ee7 Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 24 Oct 2022 12:51:54 -0400 Subject: [PATCH 04/20] remove unchanged epoch processing section --- specs/eip4844/beacon-chain.md | 45 ----------------------------------- specs/eip4844/fork.md | 2 +- 2 files changed, 1 insertion(+), 46 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index e92f932d06..78953bb363 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -27,11 +27,9 @@ - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Epoch processing](#epoch-processing) - [Block processing](#block-processing) - [Execution payload](#execution-payload) - [`process_execution_payload`](#process_execution_payload) - - [Modified `process_operations`](#modified-process_operations) - [Blob KZG commitments](#blob-kzg-commitments) - [Testing](#testing) - [Disabling Withdrawals](#disabling-withdrawals) @@ -198,27 +196,6 @@ def verify_kzg_commitments_against_transactions(transactions: Sequence[Transacti ## Beacon chain state transition function -### Epoch processing - -```python -def process_epoch(state: BeaconState) -> None: - process_justification_and_finalization(state) - process_inactivity_updates(state) - process_rewards_and_penalties(state) - process_registry_updates(state) - process_slashings(state) - process_eth1_data_reset(state) - process_effective_balance_updates(state) - process_slashings_reset(state) - process_randao_mixes_reset(state) - process_historical_roots_update(state) - process_participation_flag_updates(state) - process_sync_committee_updates(state) - process_full_withdrawals(state) - process_partial_withdrawals(state) -``` - - ### Block processing ```python @@ -271,28 +248,6 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe ) ``` -#### Modified `process_operations` - -*Note*: The function `process_operations` is modified to feature flag Withdrawals. - -```python -def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: - # Verify that outstanding deposits are processed up to the maximum number of deposits - assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) - - def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: - for operation in operations: - fn(state, operation) - - for_ops(body.proposer_slashings, process_proposer_slashing) - for_ops(body.attester_slashings, process_attester_slashing) - for_ops(body.attestations, process_attestation) - for_ops(body.deposits, process_deposit) - for_ops(body.voluntary_exits, process_voluntary_exit) - for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) -``` - - #### Blob KZG commitments ```python diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index e404265572..62908112a1 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -64,7 +64,7 @@ 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 `Capella.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: capella.BeaconState) -> BeaconState: From 459310f744e35a5ce5f2ef0188127413535cb49b Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 24 Oct 2022 16:25:50 -0400 Subject: [PATCH 05/20] Fix test_process_execution_payload --- specs/eip4844/fork.md | 6 +++--- tests/core/pyspec/eth2spec/test/context.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index 62908112a1..9d42a23025 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -111,9 +111,9 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: # Execution-layer latest_execution_payload_header=pre.latest_execution_payload_header, # Withdrawals - withdrawal_queue=[], - next_withdrawal_index=WithdrawalIndex(0), - next_partial_withdrawal_validator_index=ValidatorIndex(0), + withdrawal_queue=pre.withdrawal_queue, + next_withdrawal_index=pre.next_withdrawal_index, + next_partial_withdrawal_validator_index=pre.next_partial_withdrawal_validator_index, ) return post diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index bc04c05f2c..242a0f8911 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -14,7 +14,7 @@ PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, SHARDING, MINIMAL, MAINNET, ALL_PHASES, FORKS_BEFORE_ALTAIR, FORKS_BEFORE_BELLATRIX, - ALL_FORK_UPGRADES, + FORKS_BEFORE_CAPELLA, ALL_FORK_UPGRADES, ) from .helpers.typing import SpecForkName, PresetBaseName from .helpers.genesis import create_genesis_state @@ -596,7 +596,7 @@ def is_post_bellatrix(spec): def is_post_capella(spec): - return spec.fork == CAPELLA + return spec.fork not in FORKS_BEFORE_CAPELLA def is_post_eip4844(spec): From 6d270cdc52a5985b1d3da784a846b2f0768978a5 Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 24 Oct 2022 17:21:36 -0400 Subject: [PATCH 06/20] Add CAPELLA_FORK_EPOCH overrides --- tests/core/pyspec/eth2spec/test/context.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 242a0f8911..1172b73a46 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -305,6 +305,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 From ca538f52a05d0738cbee0e5aaa075e703724f99b Mon Sep 17 00:00:00 2001 From: Inphi Date: Tue, 25 Oct 2022 12:06:07 -0400 Subject: [PATCH 07/20] Update specs/eip4844/beacon-chain.md Co-authored-by: Alex Stokes --- specs/eip4844/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 78953bb363..1df899b813 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -312,7 +312,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, ``` ### Disabling Withdrawals -During testing we avoid Capella-specific updates the state transition. We do this by replacing the following functions with a no-op implementation: +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_full_withdrawals` - `process_partial_withdrawals` - `process_withdrawals` From 317209591deba05c7270260d4bb983ec410f593a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 26 Oct 2022 10:53:04 -0500 Subject: [PATCH 08/20] Make pyspec disable withdrawal-functions in EIP4844 --- setup.py | 28 +++++++++++++ .../test_process_bls_to_execution_change.py | 23 ++++++----- .../block_processing/test_process_deposit.py | 5 ++- .../test_process_withdrawals.py | 31 +++++++------- .../test_process_full_withdrawals.py | 33 +++++++-------- .../test_process_partial_withdrawals.py | 41 ++++++++++--------- .../test/capella/sanity/test_blocks.py | 14 +++---- tests/core/pyspec/eth2spec/test/context.py | 2 +- .../pyspec/eth2spec/test/helpers/constants.py | 1 + 9 files changed, 106 insertions(+), 72 deletions(-) diff --git a/setup.py b/setup.py index 6a58e6ff18..728f7d7ba0 100644 --- a/setup.py +++ b/setup.py @@ -617,6 +617,34 @@ 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_full_withdrawals = no_op(process_full_withdrawals) +process_partial_withdrawals = no_op(process_partial_withdrawals) +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) -> BlobsSidecar: pass''' 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 4932bc60df..a765aa8355 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 @@ -1,8 +1,9 @@ +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.execution_payload import ( build_empty_execution_payload, ) -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_capella_and_later +from eth2spec.test.context import spec_state_test, expect_assertion_error, with_phases from eth2spec.test.helpers.state import next_slot @@ -53,7 +54,7 @@ def run_withdrawals_processing(spec, state, execution_payload, valid=True): assert state.withdrawal_queue == pre_withdrawal_queue[num_withdrawals:] -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_empty_queue(spec, state): assert len(state.withdrawal_queue) == 0 @@ -64,7 +65,7 @@ def test_success_empty_queue(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_in_queue(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -75,7 +76,7 @@ def test_success_one_in_queue(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_max_per_slot_in_queue(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -86,7 +87,7 @@ def test_success_max_per_slot_in_queue(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_a_lot_in_queue(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -101,7 +102,7 @@ def test_success_a_lot_in_queue(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_empty_queue_non_empty_withdrawals(spec, state): assert len(state.withdrawal_queue) == 0 @@ -118,7 +119,7 @@ def test_fail_empty_queue_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_in_queue_none_in_withdrawals(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -130,7 +131,7 @@ def test_fail_one_in_queue_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_in_queue_two_in_withdrawals(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -142,7 +143,7 @@ def test_fail_one_in_queue_two_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_max_per_slot_in_queue_one_less_in_withdrawals(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -154,7 +155,7 @@ def test_fail_max_per_slot_in_queue_one_less_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_in_queue_too_few_in_withdrawals(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -170,7 +171,7 @@ def test_fail_a_lot_in_queue_too_few_in_withdrawals(spec, state): # 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_dequeue_index(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -182,7 +183,7 @@ def test_fail_incorrect_dequeue_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_dequeue_address(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -194,7 +195,7 @@ def test_fail_incorrect_dequeue_address(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_dequeue_amount(spec, state): prepare_withdrawal_queue(spec, state, 1) @@ -206,7 +207,7 @@ def test_fail_incorrect_dequeue_amount(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_dequeued_incorrectly(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -224,7 +225,7 @@ def test_fail_one_of_many_dequeued_incorrectly(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_dequeued_incorrectly(spec, state): prepare_withdrawal_queue(spec, state, spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_full_withdrawals.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_full_withdrawals.py index 35d2968cb9..1e1c9d60a3 100644 --- a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_full_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_full_withdrawals.py @@ -1,15 +1,16 @@ from random import Random from eth2spec.test.context import ( - with_capella_and_later, + with_phases, spec_state_test, ) -from eth2spec.test.helpers.random import ( - randomize_state, -) +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_to, ) +from eth2spec.test.helpers.random import ( + randomize_state, +) from eth2spec.test.helpers.withdrawals import ( set_validator_fully_withdrawable, ) @@ -41,7 +42,7 @@ def run_process_full_withdrawals(spec, state, num_expected_withdrawals=None): assert state.next_withdrawal_index == pre_next_withdrawal_index + num_expected_withdrawals -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_no_withdrawable_validators(spec, state): pre_validators = state.validators.copy() @@ -50,7 +51,7 @@ def test_no_withdrawable_validators(spec, state): assert pre_validators == state.validators -@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) @@ -62,7 +63,7 @@ def test_withdrawable_epoch_but_0_balance(spec, state): yield from run_process_full_withdrawals(spec, state, 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) @@ -74,7 +75,7 @@ def test_withdrawable_epoch_but_0_effective_balance_0_balance(spec, state): yield from run_process_full_withdrawals(spec, state, 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) @@ -86,7 +87,7 @@ def test_withdrawable_epoch_but_0_effective_balance_nonzero_balance(spec, state) yield from run_process_full_withdrawals(spec, state, 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) @@ -98,7 +99,7 @@ def test_no_withdrawals_but_some_next_epoch(spec, state): yield from run_process_full_withdrawals(spec, state, 0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_single_withdrawal(spec, state): # Make one validator withdrawable @@ -110,7 +111,7 @@ def test_single_withdrawal(spec, state): assert state.next_withdrawal_index == 1 -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_multi_withdrawal(spec, state): # Make a few validators withdrawable @@ -120,7 +121,7 @@ def test_multi_withdrawal(spec, state): yield from run_process_full_withdrawals(spec, state, 3) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_all_withdrawal(spec, state): # Make all validators withdrawable @@ -150,25 +151,25 @@ def run_random_full_withdrawals_test(spec, state, rng): yield from run_process_full_withdrawals(spec, state, None) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_withdrawals_0(spec, state): yield from run_random_full_withdrawals_test(spec, state, Random(444)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_withdrawals_1(spec, state): yield from run_random_full_withdrawals_test(spec, state, Random(420)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_withdrawals_2(spec, state): yield from run_random_full_withdrawals_test(spec, state, Random(200)) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_random_withdrawals_3(spec, state): yield from run_random_full_withdrawals_test(spec, state, Random(2000000)) diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_partial_withdrawals.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_partial_withdrawals.py index 7569d28621..91411b9d3a 100644 --- a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_partial_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_partial_withdrawals.py @@ -1,10 +1,11 @@ import random from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( - with_capella_and_later, + with_phases, spec_state_test, with_presets, ) +from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.epoch_processing import run_epoch_processing_to from eth2spec.test.helpers.state import next_epoch from eth2spec.test.helpers.random import randomize_state @@ -48,7 +49,7 @@ def run_process_partial_withdrawals(spec, state, num_expected_withdrawals=None): assert state.next_withdrawal_index == pre_next_withdrawal_index + num_expected_withdrawals -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_no_withdrawable(spec, state): pre_validators = state.validators.copy() @@ -57,7 +58,7 @@ def test_success_no_withdrawable(spec, state): assert pre_validators == state.validators -@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 @@ -71,7 +72,7 @@ def test_success_no_max_effective_balance(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -85,7 +86,7 @@ def test_success_no_excess_balance(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -100,7 +101,7 @@ def test_success_excess_balance_but_no_max_effective_balance(spec, state): yield from run_process_partial_withdrawals(spec, state, 0) -@with_capella_and_later +@with_phases([CAPELLA]) @spec_state_test def test_success_one_partial_withdrawable(spec, state): validator_index = len(state.validators) // 2 @@ -109,7 +110,7 @@ def test_success_one_partial_withdrawable(spec, state): yield from run_process_partial_withdrawals(spec, state, 1) -@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 @@ -121,7 +122,7 @@ def test_success_one_partial_withdrawable_not_yet_active(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -134,7 +135,7 @@ def test_success_one_partial_withdrawable_in_exit_queue(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -146,7 +147,7 @@ def test_success_one_partial_withdrawable_exited(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -158,7 +159,7 @@ def test_success_one_partial_withdrawable_active_and_slashed(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -171,7 +172,7 @@ def test_success_one_partial_withdrawable_exited_and_slashed(spec, state): yield from run_process_partial_withdrawals(spec, state, 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) @@ -180,7 +181,7 @@ def test_success_two_partial_withdrawable(spec, state): yield from run_process_partial_withdrawals(spec, state, 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 @@ -192,7 +193,7 @@ def test_success_max_partial_withdrawable(spec, state): yield from run_process_partial_withdrawals(spec, state, spec.MAX_PARTIAL_WITHDRAWALS_PER_EPOCH) -@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): @@ -226,37 +227,37 @@ def run_random_partial_withdrawals_test(spec, state, rng): yield from run_process_partial_withdrawals(spec, state) -@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_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_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_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_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_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 28c20a2cd3..c76c66e8d8 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, ) @@ -16,7 +16,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 @@ -39,7 +39,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 @@ -57,7 +57,7 @@ def test_full_withdrawal_in_epoch_transition(spec, state): assert state.balances[index] == 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 @@ -81,7 +81,7 @@ def test_partial_withdrawal_in_epoch_transition(spec, state): assert len(state.withdrawal_queue) == pre_withdrawal_queue_len -@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 @@ -106,7 +106,7 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state): assert len(state.withdrawal_queue) == pre_withdrawal_queue_len + 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 diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 1172b73a46..11ed21b102 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -606,7 +606,7 @@ def is_post_eip4844(spec): with_altair_and_later = with_all_phases_except([PHASE0]) with_bellatrix_and_later = with_all_phases_except([PHASE0, ALTAIR]) -with_capella_and_later = with_all_phases_except([PHASE0, ALTAIR, BELLATRIX, EIP4844]) +with_capella_and_later = with_all_phases_except([PHASE0, ALTAIR, BELLATRIX]) with_eip4844_and_later = with_all_phases_except([PHASE0, ALTAIR, BELLATRIX, CAPELLA]) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index b1463b97bd..bfb8ffea0b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -34,6 +34,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 not in FORKS_BEFORE_ALTAIR} From e460005aff5f8c6b4778a0c5f8090f82ed729551 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 26 Oct 2022 15:06:59 -0500 Subject: [PATCH 09/20] Add tests for no-op functions --- .../test/eip4844/block_processing/__init__.py | 0 .../test_process_bls_to_execution_change.py | 40 +++++++++++++++++ .../test/eip4844/epoch_processing/__init__.py | 0 .../test_process_full_withdrawals.py | 43 +++++++++++++++++++ .../test_process_partial_withdrawals.py | 43 +++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py 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/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py new file mode 100644 index 0000000000..1a7cda91da --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py @@ -0,0 +1,43 @@ +from eth2spec.test.context import ( + with_eip4844_and_later, + spec_state_test, +) +from eth2spec.test.helpers.epoch_processing import ( + run_epoch_processing_to, +) +from eth2spec.test.helpers.withdrawals import ( + set_validator_fully_withdrawable, +) + + +def run_process_full_withdrawals_no_op(spec, state, num_expected_withdrawals=None): + run_epoch_processing_to(spec, state, 'process_full_withdrawals') + + state.next_withdrawal_index = 0 + to_be_withdrawn_indices = [ + index for index, validator in enumerate(state.validators) + if spec.is_fully_withdrawable_validator(validator, state.balances[index], spec.get_current_epoch(state)) + ] + + if num_expected_withdrawals is not None: + assert len(to_be_withdrawn_indices) == num_expected_withdrawals + else: + num_expected_withdrawals = len(to_be_withdrawn_indices) + + pre_state = state.copy() + + yield 'pre', state + spec.process_full_withdrawals(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): + # Make one validator withdrawable + set_validator_fully_withdrawable(spec, state, 0) + + yield from run_process_full_withdrawals_no_op(spec, state, 1) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py new file mode 100644 index 0000000000..9921334206 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py @@ -0,0 +1,43 @@ +from eth2spec.test.context import ( + spec_state_test, + with_eip4844_and_later, +) +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_to +from eth2spec.test.helpers.withdrawals import ( + set_validator_partially_withdrawable, +) + + +def run_process_partial_withdrawals_no_op(spec, state, num_expected_withdrawals=None): + # Run rest of epoch processing before predicting partial withdrawals as + # balance changes can affect withdrawability + run_epoch_processing_to(spec, state, 'process_partial_withdrawals') + + partially_withdrawable_indices = [ + index for index, validator in enumerate(state.validators) + if spec.is_partially_withdrawable_validator(validator, state.balances[index]) + ] + num_partial_withdrawals = min(len(partially_withdrawable_indices), spec.MAX_PARTIAL_WITHDRAWALS_PER_EPOCH) + + if num_expected_withdrawals is not None: + assert num_partial_withdrawals == num_expected_withdrawals + else: + num_expected_withdrawals = num_partial_withdrawals + + pre_state = state.copy() + + yield 'pre', state + spec.process_partial_withdrawals(state) + yield 'post', state + + # Make sure state has NOT been changed + assert state == pre_state + + +@with_eip4844_and_later +@spec_state_test +def test_success_one_partial_withdrawable(spec, state): + validator_index = len(state.validators) // 2 + set_validator_partially_withdrawable(spec, state, validator_index) + + yield from run_process_partial_withdrawals_no_op(spec, state, 1) From 60187e5dc4d12137e3441933a63903344750704c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 26 Oct 2022 15:19:15 -0500 Subject: [PATCH 10/20] Add `test_process_withdrawals` no-op test --- .../test_process_withdrawals.py | 57 +++++++++++++++++++ .../test_process_partial_withdrawals.py | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py 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..86ac7e4aeb --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py @@ -0,0 +1,57 @@ + +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 prepare_withdrawal_queue(spec, state, num_withdrawals): + pre_queue_len = len(state.withdrawal_queue) + + for i in range(num_withdrawals): + withdrawal = spec.Withdrawal( + index=i + 5, + address=b'\x42' * 20, + amount=200000 + i, + ) + state.withdrawal_queue.append(withdrawal) + + assert len(state.withdrawal_queue) == num_withdrawals + pre_queue_len + + +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): + prepare_withdrawal_queue(spec, state, 1) + + 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/eip4844/epoch_processing/test_process_partial_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py index 9921334206..78be3eb6cc 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py @@ -36,7 +36,7 @@ def run_process_partial_withdrawals_no_op(spec, state, num_expected_withdrawals= @with_eip4844_and_later @spec_state_test -def test_success_one_partial_withdrawable(spec, state): +def test_no_op(spec, state): validator_index = len(state.validators) // 2 set_validator_partially_withdrawable(spec, state, validator_index) From e3e73a8f5484a35a9e491b64134bc6275be06996 Mon Sep 17 00:00:00 2001 From: inphi Date: Tue, 8 Nov 2022 09:06:38 -0500 Subject: [PATCH 11/20] Add Capella fork version --- specs/eip4844/p2p-interface.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index f861ed28b6..2a87869692 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -123,6 +123,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 @@ -140,6 +141,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` | #### BlobsSidecarsByRange v1 From a04f06bd11cc782c8f02d2890e2a4a51b2d311e8 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 10 Nov 2022 13:29:33 -0500 Subject: [PATCH 12/20] Fix merge conflict --- setup.py | 2 -- tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 589b5fdf13..205e8c400f 100644 --- a/setup.py +++ b/setup.py @@ -669,8 +669,6 @@ def wrapper(*args, **kw): # type: ignore return wrapper -process_full_withdrawals = no_op(process_full_withdrawals) -process_partial_withdrawals = no_op(process_partial_withdrawals) 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) 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 6ca2e9432f..3c406e524d 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -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) From bed1df00a2452d4f0f6d26f8f2b70b35fb1b461c Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 10 Nov 2022 13:57:30 -0500 Subject: [PATCH 13/20] Remove withdrawal_queue from BeaconState upgrade --- specs/eip4844/fork.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index b13eb5a321..bdd26e8115 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -111,7 +111,6 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: # Execution-layer latest_execution_payload_header=pre.latest_execution_payload_header, # Withdrawals - withdrawal_queue=pre.withdrawal_queue, next_withdrawal_index=pre.next_withdrawal_index, next_withdrawal_validator_index=pre.next_withdrawal_validator_index, ) From 2fbb1eddd2e9b064c794c826c73cd0004af832da Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 10 Nov 2022 14:01:50 -0500 Subject: [PATCH 14/20] fix test_process_withdrawals --- .../block_processing/test_process_withdrawals.py | 16 ---------------- 1 file changed, 16 deletions(-) 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 index 86ac7e4aeb..a7db37e422 100644 --- 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 @@ -6,20 +6,6 @@ from eth2spec.test.helpers.state import next_slot -def prepare_withdrawal_queue(spec, state, num_withdrawals): - pre_queue_len = len(state.withdrawal_queue) - - for i in range(num_withdrawals): - withdrawal = spec.Withdrawal( - index=i + 5, - address=b'\x42' * 20, - amount=200000 + i, - ) - state.withdrawal_queue.append(withdrawal) - - assert len(state.withdrawal_queue) == num_withdrawals + pre_queue_len - - def run_withdrawals_processing(spec, state, execution_payload, valid=True): """ Run ``process_execution_payload``, yielding: @@ -49,8 +35,6 @@ def run_withdrawals_processing(spec, state, execution_payload, valid=True): @with_eip4844_and_later @spec_state_test def test_no_op(spec, state): - prepare_withdrawal_queue(spec, state, 1) - next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) From fcafdc14a388373c12e59a0c72d169b83b865b5e Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 10 Nov 2022 14:11:05 -0500 Subject: [PATCH 15/20] remove eip4844 partial/full withdrawwals tests --- .../test_process_full_withdrawals.py | 43 ------------------- .../test_process_partial_withdrawals.py | 43 ------------------- 2 files changed, 86 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py deleted file mode 100644 index 1a7cda91da..0000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_full_withdrawals.py +++ /dev/null @@ -1,43 +0,0 @@ -from eth2spec.test.context import ( - with_eip4844_and_later, - spec_state_test, -) -from eth2spec.test.helpers.epoch_processing import ( - run_epoch_processing_to, -) -from eth2spec.test.helpers.withdrawals import ( - set_validator_fully_withdrawable, -) - - -def run_process_full_withdrawals_no_op(spec, state, num_expected_withdrawals=None): - run_epoch_processing_to(spec, state, 'process_full_withdrawals') - - state.next_withdrawal_index = 0 - to_be_withdrawn_indices = [ - index for index, validator in enumerate(state.validators) - if spec.is_fully_withdrawable_validator(validator, state.balances[index], spec.get_current_epoch(state)) - ] - - if num_expected_withdrawals is not None: - assert len(to_be_withdrawn_indices) == num_expected_withdrawals - else: - num_expected_withdrawals = len(to_be_withdrawn_indices) - - pre_state = state.copy() - - yield 'pre', state - spec.process_full_withdrawals(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): - # Make one validator withdrawable - set_validator_fully_withdrawable(spec, state, 0) - - yield from run_process_full_withdrawals_no_op(spec, state, 1) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py deleted file mode 100644 index 78be3eb6cc..0000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_partial_withdrawals.py +++ /dev/null @@ -1,43 +0,0 @@ -from eth2spec.test.context import ( - spec_state_test, - with_eip4844_and_later, -) -from eth2spec.test.helpers.epoch_processing import run_epoch_processing_to -from eth2spec.test.helpers.withdrawals import ( - set_validator_partially_withdrawable, -) - - -def run_process_partial_withdrawals_no_op(spec, state, num_expected_withdrawals=None): - # Run rest of epoch processing before predicting partial withdrawals as - # balance changes can affect withdrawability - run_epoch_processing_to(spec, state, 'process_partial_withdrawals') - - partially_withdrawable_indices = [ - index for index, validator in enumerate(state.validators) - if spec.is_partially_withdrawable_validator(validator, state.balances[index]) - ] - num_partial_withdrawals = min(len(partially_withdrawable_indices), spec.MAX_PARTIAL_WITHDRAWALS_PER_EPOCH) - - if num_expected_withdrawals is not None: - assert num_partial_withdrawals == num_expected_withdrawals - else: - num_expected_withdrawals = num_partial_withdrawals - - pre_state = state.copy() - - yield 'pre', state - spec.process_partial_withdrawals(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): - validator_index = len(state.validators) // 2 - set_validator_partially_withdrawable(spec, state, validator_index) - - yield from run_process_partial_withdrawals_no_op(spec, state, 1) From 67ba28c9d0f18ae7645219afcabbcfade9352869 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 10 Nov 2022 14:13:49 -0500 Subject: [PATCH 16/20] remove eip4844 epoch_processing package --- .../pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 From 104cba06a6ab38a32d00423ceae55b41ba8e0944 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 11 Nov 2022 00:21:56 -0500 Subject: [PATCH 17/20] replace get_blobs_and_kzg_commitments --- specs/eip4844/validator.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index c919c6f187..57a5610ce4 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -11,9 +11,7 @@ - [Introduction](#introduction) - [Prerequisites](#prerequisites) - [Helpers](#helpers) -- [Protocols](#protocols) - - [`ExecutionEngine`](#executionengine) - - [`get_payload`](#get_payload) + - [`get_blobs_and_kzg_commitments`](#get_blobs_and_kzg_commitments) - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block and sidecar proposal](#block-and-sidecar-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) @@ -39,13 +37,17 @@ Please see related Beacon Chain doc before continuing and use them as a referenc ## Helpers -## Protocols +### `get_blobs_and_kzg_commitments` -### `ExecutionEngine` +The interface to retrieve blobs and corresponding kzg commitments. -#### `get_payload` +Note: This API is *unstable*. `get_blobs_and_kzg_commitments` and `get_payload` may be unified. +Implementers may also retrieve blobs individually per transaction. -`get_payload` returns the upgraded EIP-4844 `ExecutionPayload` type. +```python +def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment]]: + ... +``` ## Beacon chain responsibilities From 6327ffa687aac88d5f11f51294fb1c7afcf4d2d9 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 11 Nov 2022 17:24:05 -0500 Subject: [PATCH 18/20] rename excess_blobs --- specs/eip4844/beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 69cf4ff31a..b9a46f7cbc 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -111,7 +111,7 @@ 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: uint64 # [New in EIP-4844] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] @@ -135,7 +135,7 @@ 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: uint64 # [New in EIP-4844] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root @@ -273,7 +273,7 @@ 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), From cd1e1133a5f1830480c5bfc81af22b9c49055859 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 11 Nov 2022 17:25:06 -0500 Subject: [PATCH 19/20] excess_data_gas uint256 --- specs/eip4844/beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index b9a46f7cbc..4a6d4203b4 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -111,7 +111,7 @@ class ExecutionPayload(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: 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] @@ -135,7 +135,7 @@ class ExecutionPayloadHeader(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: 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 From 37144460be5a55249469bfe7beb3d5cb34a13e19 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 11 Nov 2022 17:52:57 -0500 Subject: [PATCH 20/20] Fix merge conflict --- tests/core/pyspec/eth2spec/test/helpers/forks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: