From d46d27514a9bfba509be8f0d9dd310fdca593a45 Mon Sep 17 00:00:00 2001 From: Manu NALEPA Date: Tue, 2 Apr 2024 13:40:24 +0200 Subject: [PATCH 001/141] `p2p-interface.md`: Add `quic` ENR entry. --- specs/phase0/p2p-interface.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index ff1bd03a1d..e8c2ce9d63 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -959,7 +959,8 @@ The Ethereum Node Record (ENR) for an Ethereum consensus client MUST contain the The ENR MAY contain the following entries: - An IPv4 address (`ip` field) and/or IPv6 address (`ip6` field). -- A TCP port (`tcp` field) representing the local libp2p listening port. +- A TCP port (`tcp` field) representing the local libp2p TCP listening port. +- A QUIC port (`quic` field) representing the local libp2p QUIC (UDP) listening port. - A UDP port (`udp` field) representing the local discv5 listening port. Specifications of these parameters can be found in the [ENR Specification](http://eips.ethereum.org/EIPS/eip-778). From 093f5f39f1de63257a87dc43bafbdca27b8bd972 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 12 Jun 2024 09:56:08 -0600 Subject: [PATCH 002/141] EIP-7742: uncouple blob counts across CL and EL --- pysetup/spec_builders/electra.py | 49 +++++++++++++++++++++++++---- specs/electra/beacon-chain.md | 53 ++++++++++++++++++++++++++++++++ specs/electra/fork-choice.md | 37 ++++++++++++++++++++++ specs/electra/validator.md | 1 + 4 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 specs/electra/fork-choice.md diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index 1f968a817d..3d4d06f5e4 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -8,16 +8,53 @@ class ElectraSpecBuilder(BaseSpecBuilder): @classmethod def imports(cls, preset_name: str): - return f''' + return f""" from eth2spec.deneb import {preset_name} as deneb -''' +""" -## TODO: deal with changed gindices + @classmethod + def execution_engine_cls(cls) -> str: + return """ +class NoopExecutionEngine(ExecutionEngine): + + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root, + target_blobs_per_block: uint64) -> bool: + return True + + def notify_forkchoice_updated(self: ExecutionEngine, + head_block_hash: Hash32, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]: + pass + + def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse: + # pylint: disable=unused-argument + raise NotImplementedError("no default block production") + + def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + return True + + def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: + return True + + def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + return True + + +EXECUTION_ENGINE = NoopExecutionEngine()""" + + ## TODO: deal with changed gindices @classmethod def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: return { - 'FINALIZED_ROOT_GINDEX': 'GeneralizedIndex(169)', - 'CURRENT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(86)', - 'NEXT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(87)', + "FINALIZED_ROOT_GINDEX": "GeneralizedIndex(169)", + "CURRENT_SYNC_COMMITTEE_GINDEX": "GeneralizedIndex(86)", + "NEXT_SYNC_COMMITTEE_GINDEX": "GeneralizedIndex(87)", } diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index d9e9d1f27b..41a988b367 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -67,6 +67,11 @@ - [New `compute_consolidation_epoch_and_update_churn`](#new-compute_consolidation_epoch_and_update_churn) - [Updated `slash_validator`](#updated-slash_validator) - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Execution engine](#execution-engine) + - [Request data](#request-data) + - [Engine APIs](#engine-apis) + - [Modified `notify_new_payload`](#modified-notify_new_payload) + - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Epoch processing](#epoch-processing) - [Updated `process_epoch`](#updated-process_epoch) - [Updated `process_registry_updates`](#updated--process_registry_updates) @@ -758,6 +763,54 @@ def slash_validator(state: BeaconState, ## Beacon chain state transition function +### Execution engine + +#### Request data + +#### Engine APIs + +##### Modified `notify_new_payload` + +*Note*: The function `notify_new_payload` is modified to include the target number of blobs +allowed per block. + +```python +def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root, + target_blobs_per_block: uint64) -> bool: + """ + Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. + """ + ... +``` + +##### Modified `verify_and_notify_new_payload` + +```python +def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + """ + Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. + """ + execution_payload = new_payload_request.execution_payload + parent_beacon_block_root = new_payload_request.parent_beacon_block_root + + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): + return False + + if not self.is_valid_versioned_hashes(new_payload_request): + return False + + # [Modified in Electra] + if not self.notify_new_payload(execution_payload, + parent_beacon_block_root, + MAX_BLOBS_PER_BLOCK // 2): + return False + + return True +``` + ### Epoch processing #### Updated `process_epoch` diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md new file mode 100644 index 0000000000..9737a68a9f --- /dev/null +++ b/specs/electra/fork-choice.md @@ -0,0 +1,37 @@ +# Electra -- Fork Choice + +## Table of contents + + + + +- [Introduction](#introduction) +- [Containers](#containers) +- [Helpers](#helpers) + - [Extended `PayloadAttributes`](#extended-payloadattributes) + + + + +## Introduction + +This is the modification of the fork choice accompanying the Electra upgrade. + +## Containers + +## Helpers + +### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the maximum number of blobs per block. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root + target_blobs_per_block: uint64 # [New in Electra] +``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index f589e963c5..6d31856ac4 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -139,6 +139,7 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), + target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From 95ddd1567af355bd3204677272a09b16bd79320a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 22 Jul 2024 20:02:01 +0200 Subject: [PATCH 003/141] Document `ForkDigest`-context for EIP-4844 `BlobSidecar` in Electra Currently, documentation does not state what determines the `ForkDigest` for `BlobSidecar`. It makes most sense to use the corresponding slot as that one determines the `ForkDigest` of the corresponding beacon block. Furthermore, add "and later" remarks so that `ELECTRA_FORK_VERSION` is also associated with the `deneb.BlobSidecar` type. This is in line with how `light-client/p2p-interface.md` is done. --- specs/deneb/p2p-interface.md | 49 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 41e2fa9d3f..8501f599d0 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -187,6 +187,16 @@ The following validations MUST pass before forwarding the `blob_sidecar` on the - _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `block_header.parent_root`/`block_header.slot`). If the `proposer_index` cannot immediately be verified against the expected shuffling, the sidecar MAY be queued for later processing while proposers for the block's branch are calculated -- in such a case _do not_ `REJECT`, instead `IGNORE` this message. +The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))`. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------------|-------------------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | + ##### Attestation subnets ###### `beacon_attestation_{subnet_id}` @@ -241,7 +251,7 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: -[1]: # (eth2spec: skip) +[0]: # (eth2spec: skip) | `fork_version` | Chunk SSZ type | |--------------------------|-------------------------------| @@ -263,14 +273,6 @@ Clients SHOULD NOT respond with blocks that fail the beacon chain state transiti *[New in Deneb:EIP4844]* -The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: - -[1]: # (eth2spec: skip) - -| `fork_version` | Chunk SSZ type | -|--------------------------|-------------------------------| -| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | - Request Content: ``` @@ -309,19 +311,22 @@ Clients SHOULD include a sidecar in the response as soon as it passes the gossip Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition -##### BlobSidecarsByRange v1 +For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))` is used to select the fork namespace of the Response type. -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: -*[New in Deneb:EIP4844]* +[0]: # (eth2spec: skip) -The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: +| `fork_version` | Chunk SSZ type | +|--------------------------------|-------------------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | -[1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------|-------------------------------| -| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | +##### BlobSidecarsByRange v1 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` + +*[New in Deneb:EIP4844]* Request Content: ``` @@ -389,6 +394,16 @@ Clients MUST respond with blob sidecars that are consistent from a single chain After the initial blob sidecar, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request. +For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))` is used to select the fork namespace of the Response type. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------------|-------------------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | + ## Design decision rationale ### Why are blobs relayed as a sidecar, separate from beacon blocks? From dec28c1322356b8b39970bf7771df72ec0ffbe02 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 24 Jul 2024 16:53:46 +0200 Subject: [PATCH 004/141] Rename to `ForkDigestValue` for Gossipsub topics --- specs/altair/light-client/p2p-interface.md | 4 ++-- specs/deneb/p2p-interface.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index c33d887a50..e1fe7487db 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -71,7 +71,7 @@ For light clients, the following validations MUST additionally pass before forwa Light clients SHOULD call `process_light_client_finality_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.beacon.slot))`. +The gossip `ForkDigestValue` is determined based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.beacon.slot))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -99,7 +99,7 @@ For light clients, the following validations MUST additionally pass before forwa Light clients SHOULD call `process_light_client_optimistic_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.beacon.slot))`. +The gossip `ForkDigestValue` is determined based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.beacon.slot))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 8501f599d0..7af3faa22d 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -187,7 +187,7 @@ The following validations MUST pass before forwarding the `blob_sidecar` on the - _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `block_header.parent_root`/`block_header.slot`). If the `proposer_index` cannot immediately be verified against the expected shuffling, the sidecar MAY be queued for later processing while proposers for the block's branch are calculated -- in such a case _do not_ `REJECT`, instead `IGNORE` this message. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))`. +The gossip `ForkDigestValue` is determined based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: From e1eaa7ffa194f70f044970689b11b27c9d68cb66 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 14 Aug 2024 22:55:05 +0200 Subject: [PATCH 005/141] Synchronously check all `transactions` to have non-zero length As part of `newPayload` block hash verification, the `transactionsRoot` is computed by the EL. Because Merkle-Patricia Tries cannot contain `[]` entries, MPT implementations typically treat setting a key to `[]` as deleting the entry for the key. This means that if a CL receives a block with `transactions` containing one or more zero-length transactions, that such transactions will effectively be skipped when computing the `transactionsRoot`. Note that `transactions` are opaque to the CL and zero-length transactions are not filtered out before `newPayload`. ```python # https://eips.ethereum.org/EIPS/eip-2718 def compute_trie_root_from_indexed_data(data): """ Computes the root hash of `patriciaTrie(rlp(Index) => Data)` for a data array. """ t = HexaryTrie(db={}) for i, obj in enumerate(data): k = encode(i, big_endian_int) t.set(k, obj) # Implicitly skipped if `obj == b''` (invalid RLP) return t.root_hash ``` In any case, the `blockHash` validation may still succeed, resulting in a potential `SYNCING/ACCEPTED` result to `newPayload` by spec. Note, however, that there is an effective hash collision if a payload is modified by appending one or more zero-length transactions to the end of `transactions` list: In the trivial case, a block with zero transactions has the same `transactionsRoot` (and `blockHash`) as one of a block with one `[]` transaction (as that one is skipped). This means that the same `blockHash` can refer to a valid block (without extra `[]` transactions added), but also can refer to an invalid block. Because `forkchoiceUpdated` refers to blocks by `blockHash`, outcome may be nondeterministic and implementation dependent. If `forkchoiceUpdated` deems the `blockHash` to refer to a `VALID` object (obtained from a src that does not have the extra `[]` transactions, e.g., devp2p), then this could result in honest attestations to a CL beacon block with invalid `[]` transactions in its `ExecutionPayload`, risking finalizing it. The problem can be avoided by returning `INVALID` in `newPayload` if there are any zero-length `transactions` entries, preventing optimistic import of such blocks by the CL. --- specs/bellatrix/beacon-chain.md | 11 +++++++++-- specs/deneb/beacon-chain.md | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/specs/bellatrix/beacon-chain.md b/specs/bellatrix/beacon-chain.md index 6f67be96a7..51d570fe2d 100644 --- a/specs/bellatrix/beacon-chain.md +++ b/specs/bellatrix/beacon-chain.md @@ -355,10 +355,17 @@ def verify_and_notify_new_payload(self: ExecutionEngine, """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ - if not self.is_valid_block_hash(new_payload_request.execution_payload): + execution_payload = new_payload_request.execution_payload + + if b'' in execution_payload.transactions: return False - if not self.notify_new_payload(new_payload_request.execution_payload): + + if not self.is_valid_block_hash(execution_payload): return False + + if not self.notify_new_payload(execution_payload): + return False + return True ``` diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 0f6a8fc076..1b7a322c2f 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -293,9 +293,13 @@ def verify_and_notify_new_payload(self: ExecutionEngine, """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ + # [Modified in Deneb:EIP4788] execution_payload = new_payload_request.execution_payload parent_beacon_block_root = new_payload_request.parent_beacon_block_root + if b'' in execution_payload.transactions: + return False + # [Modified in Deneb:EIP4788] if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False From 87b5f1a969dd309ce61d3e06bd7e5f924f4b9f89 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 22 Aug 2024 14:06:00 -0600 Subject: [PATCH 006/141] updates to send maximum blob count --- specs/electra/fork-choice.md | 3 ++- specs/electra/validator.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index 9737a68a9f..8b61e124d1 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -33,5 +33,6 @@ class PayloadAttributes(object): suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root - target_blobs_per_block: uint64 # [New in Electra] + target_blob_count: uint64 # [New in Electra] + maximum_blob_count: uint64 # [New in Electra] ``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 6d31856ac4..2750c1ec26 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -139,7 +139,8 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra] + target_blob_count=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra] + maximum_blob_count=MAX_BLOBS_PER_BLOCK, # [New in Electra] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From cbc4b5530fba3aaed156a0f255a722e9bae892e4 Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Sat, 29 Jun 2024 16:45:29 +0700 Subject: [PATCH 007/141] EIP-7594: Decouple network subnets from das-core Currently we use subnets as a unit of custody in the PeerDAS core protocol because it doesn't make sense to partially custody only some columns in the subnets and waste the bandwidth to download the columns the node doesn't custody. Since subnets correspond to GossipSub topics which are in a layer lower than the core protocol, using subnets as a unit of custody makes the core layer and the network layer too coupled to each other and leave no room for the network layer flexibility. This commit introduces "custody groups" which are used a unit of custody instead of subnets. The immediate benefit of the decoupling is that we can immediately increase the number of subnets without affecting the expected number of peers to cover all columns and affecting the network stability and without touching the core protocol. The reason we want to increase the number of subnets to match the number of columns is that the columns will be propagated through the network faster when they have their own subnets. Just like EIP-4844, each blob has its own subnet because, if all the blobs are in a single subnet, the blobs will be propagated more slowly. Since we keep the number of custody groups the same as the previous number of subnets (32), the expected number of peers you need to cover all the columns is not changed. In fact, you need only NUMBER_OF_COLUMNS and NUMBER_OF_CUSTODY_GROUPS to analyze the expected number, which makes the core protocol completely decoupled from the network layer. --- configs/mainnet.yaml | 1 + configs/minimal.yaml | 1 + specs/_features/eip7594/das-core.md | 77 ++++++++++--------- specs/_features/eip7594/p2p-interface.md | 9 ++- specs/_features/eip7594/peer-sampling.md | 4 +- .../networking/test_get_custody_columns.py | 43 ++++++----- .../test/eip7594/unittests/test_custody.py | 43 +++++++---- tests/formats/networking/README.md | 3 +- .../compute_columns_for_custody_group.md | 13 ++++ ...stody_columns.md => get_custody_groups.md} | 8 +- tests/generators/networking/main.py | 3 +- 11 files changed, 124 insertions(+), 81 deletions(-) create mode 100644 tests/formats/networking/compute_columns_for_custody_group.md rename tests/formats/networking/{get_custody_columns.md => get_custody_groups.md} (53%) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 56c20a439c..d4772fd1df 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -161,6 +161,7 @@ WHISK_PROPOSER_SELECTION_GAP: 2 # EIP7594 NUMBER_OF_COLUMNS: 128 +NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index a2b4f2e736..967643c075 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -160,6 +160,7 @@ WHISK_PROPOSER_SELECTION_GAP: 1 # EIP7594 NUMBER_OF_COLUMNS: 128 +NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 diff --git a/specs/_features/eip7594/das-core.md b/specs/_features/eip7594/das-core.md index 25e58a1334..d942ce9aae 100644 --- a/specs/_features/eip7594/das-core.md +++ b/specs/_features/eip7594/das-core.md @@ -13,27 +13,28 @@ - [Custom types](#custom-types) - [Configuration](#configuration) - [Data size](#data-size) - - [Networking](#networking) - [Custody setting](#custody-setting) - [Containers](#containers) - [`DataColumnSidecar`](#datacolumnsidecar) - [`MatrixEntry`](#matrixentry) - [Helper functions](#helper-functions) - - [`get_custody_columns`](#get_custody_columns) + - [`get_custody_groups`](#get_custody_groups) + - [`compute_columns_for_custody_group`](#compute_columns_for_custody_group) - [`compute_matrix`](#compute_matrix) - [`recover_matrix`](#recover_matrix) - [`get_data_column_sidecars`](#get_data_column_sidecars) - [Custody](#custody) - [Custody requirement](#custody-requirement) - [Public, deterministic selection](#public-deterministic-selection) -- [Subnet sampling](#subnet-sampling) +- [Custody sampling](#custody-sampling) - [Extended data](#extended-data) - [Column gossip](#column-gossip) - [Parameters](#parameters) - [Reconstruction and cross-seeding](#reconstruction-and-cross-seeding) - [FAQs](#faqs) - - [Row (blob) custody](#row-blob-custody) - - [Subnet stability](#subnet-stability) + - [Why don't nodes custody rows?](#why-dont-nodes-custody-rows) + - [Why don't we rotate custody over time?](#why-dont-we-rotate-custody-over-time) + - [Does having a lot of column subnets make the network unstable?](#does-having-a-lot-of-column-subnets-make-the-network-unstable) @@ -54,6 +55,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | - | | `RowIndex` | `uint64` | Row identifier in the matrix of cells | | `ColumnIndex` | `uint64` | Column identifier in the matrix of cells | +| `CustodyIndex` | `uint64` | Custody group identifier in the set of custody groups | ## Configuration @@ -63,18 +65,13 @@ The following values are (non-configurable) constants used throughout the specif | - | - | - | | `NUMBER_OF_COLUMNS` | `uint64(CELLS_PER_EXT_BLOB)` (= 128) | Number of columns in the extended data matrix | -### Networking - -| Name | Value | Description | -| - | - | - | -| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `uint64(128)` | The number of data column sidecar subnets used in the gossipsub protocol | - ### Custody setting | Name | Value | Description | | - | - | - | | `SAMPLES_PER_SLOT` | `8` | Number of `DataColumnSidecar` random samples a node queries per slot | -| `CUSTODY_REQUIREMENT` | `4` | Minimum number of subnets an honest node custodies and serves samples from | +| `NUMBER_OF_CUSTODY_GROUPS` | `128` | Number of custody groups available for nodes to custody | +| `CUSTODY_REQUIREMENT` | `4` | Minimum number of custody groups an honest node custodies and serves samples from | ### Containers @@ -102,33 +99,39 @@ class MatrixEntry(Container): ## Helper functions -### `get_custody_columns` +### `get_custody_groups` ```python -def get_custody_columns(node_id: NodeID, custody_subnet_count: uint64) -> Sequence[ColumnIndex]: - assert custody_subnet_count <= DATA_COLUMN_SIDECAR_SUBNET_COUNT +def get_custody_groups(node_id: NodeID, custody_group_count: uint64) -> Sequence[CustodyIndex]: + assert custody_group_count <= NUMBER_OF_CUSTODY_GROUPS - subnet_ids: List[uint64] = [] + custody_groups: List[uint64] = [] current_id = uint256(node_id) - while len(subnet_ids) < custody_subnet_count: - subnet_id = ( + while len(custody_groups) < custody_group_count: + custody_group = CustodyIndex( bytes_to_uint64(hash(uint_to_bytes(uint256(current_id)))[0:8]) - % DATA_COLUMN_SIDECAR_SUBNET_COUNT + % NUMBER_OF_CUSTODY_GROUPS ) - if subnet_id not in subnet_ids: - subnet_ids.append(subnet_id) + if custody_group not in custody_groups: + custody_groups.append(custody_group) if current_id == UINT256_MAX: # Overflow prevention current_id = NodeID(0) current_id += 1 - assert len(subnet_ids) == len(set(subnet_ids)) + assert len(custody_groups) == len(set(custody_groups)) + return sorted(custody_groups) +``` - columns_per_subnet = NUMBER_OF_COLUMNS // DATA_COLUMN_SIDECAR_SUBNET_COUNT +### `compute_columns_for_custody_group` + +```python +def compute_columns_for_custody_group(custody_group: CustodyIndex) -> Sequence[ColumnIndex]: + assert custody_group < NUMBER_OF_CUSTODY_GROUPS + columns_per_group = NUMBER_OF_COLUMNS // NUMBER_OF_CUSTODY_GROUPS return sorted([ - ColumnIndex(DATA_COLUMN_SIDECAR_SUBNET_COUNT * i + subnet_id) - for i in range(columns_per_subnet) - for subnet_id in subnet_ids + ColumnIndex(NUMBER_OF_CUSTODY_GROUPS * i + custody_group) + for i in range(columns_per_group) ]) ``` @@ -220,21 +223,21 @@ def get_data_column_sidecars(signed_block: SignedBeaconBlock, ### Custody requirement -Each node downloads and custodies a minimum of `CUSTODY_REQUIREMENT` subnets per slot. The particular subnets that the node is required to custody are selected pseudo-randomly (more on this below). +Columns are grouped into custody groups. Nodes custodying a custody group MUST custody all the columns in that group. -A node *may* choose to custody and serve more than the minimum honesty requirement. Such a node explicitly advertises a number greater than `CUSTODY_REQUIREMENT` through the peer discovery mechanism, specifically by setting a higher value in the `custody_subnet_count` field within its ENR. This value can be increased up to `DATA_COLUMN_SIDECAR_SUBNET_COUNT`, indicating a super-full node. +A node *may* choose to custody and serve more than the minimum honesty requirement. Such a node explicitly advertises a number greater than `CUSTODY_REQUIREMENT` through the peer discovery mechanism, specifically by setting a higher value in the `custody_group_count` field within its ENR. This value can be increased up to `NUMBER_OF_CUSTODY_GROUPS`, indicating a super-full node. A node stores the custodied columns for the duration of the pruning period and responds to peer requests for samples on those columns. ### Public, deterministic selection -The particular columns that a node custodies are selected pseudo-randomly as a function (`get_custody_columns`) of the node-id and custody size -- importantly this function can be run by any party as the inputs are all public. +The particular columns/groups that a node custodies are selected pseudo-randomly as a function (`get_custody_groups`) of the node-id and custody size -- importantly this function can be run by any party as the inputs are all public. *Note*: increasing the `custody_size` parameter for a given `node_id` extends the returned list (rather than being an entirely new shuffle) such that if `custody_size` is unknown, the default `CUSTODY_REQUIREMENT` will be correct for a subset of the node's custody. -## Subnet sampling +## Custody sampling -At each slot, a node advertising `custody_subnet_count` downloads a minimum of `subnet_sampling_size = max(SAMPLES_PER_SLOT, custody_subnet_count)` total subnets. The corresponding set of columns is selected by `get_custody_columns(node_id, subnet_sampling_size)`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_columns(node_id, custody_subnet_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. +At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count)` total custody groups. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. ## Extended data @@ -246,7 +249,7 @@ In this construction, we extend the blobs using a one-dimensional erasure coding For each column -- use `data_column_sidecar_{subnet_id}` subnets, where `subnet_id` can be computed with the `compute_subnet_for_data_column_sidecar(column_index: ColumnIndex)` helper. The sidecars can be computed with the `get_data_column_sidecars(signed_block: SignedBeaconBlock, blobs: Sequence[Blob])` helper. -Verifiable samples from their respective column are distributed on the assigned subnet. To custody a particular column, a node joins the respective gossipsub subnet. If a node fails to get a column on the column subnet, a node can also utilize the Req/Resp protocol to query the missing column from other peers. +Verifiable samples from their respective column are distributed on the assigned subnet. To custody columns in a particular custody group, a node joins the respective gossipsub subnets. If a node fails to get columns on the column subnets, a node can also utilize the Req/Resp protocol to query the missing columns from other peers. ## Reconstruction and cross-seeding @@ -262,7 +265,7 @@ Once the node obtains a column through reconstruction, the node MUST expose the ## FAQs -### Row (blob) custody +### Why don't nodes custody rows? In the one-dimension construction, a node samples the peers by requesting the whole `DataColumnSidecar`. In reconstruction, a node can reconstruct all the blobs by 50% of the columns. Note that nodes can still download the row via `blob_sidecar_{subnet_id}` subnets. @@ -273,6 +276,10 @@ The potential benefits of having row custody could include: However, for simplicity, we don't assign row custody assignments to nodes in the current design. -### Subnet stability +### Why don't we rotate custody over time? + +To start with a simple, stable backbone, for now, we don't shuffle the custody assignments via the deterministic custody selection helper `get_custody_groups`. However, staggered rotation likely needs to happen on the order of the pruning period to ensure subnets can be utilized for recovery. For example, introducing an `epoch` argument allows the function to maintain stability over many epochs. + +### Does having a lot of column subnets make the network unstable? -To start with a simple, stable backbone, for now, we don't shuffle the subnet assignments via the deterministic custody selection helper `get_custody_columns`. However, staggered rotation likely needs to happen on the order of the pruning period to ensure subnets can be utilized for recovery. For example, introducing an `epoch` argument allows the function to maintain stability over many epochs. +No, the number of subnets doesn't really matter. What matters to the network stability is the number of nodes and the churn rate in the network. If the number of the nodes is too low, it's likely to have a network partition when some nodes are down. For the churn rate, if the churn rate is high, we even need to have a higher number of nodes, since nodes are likely to be turned off more often. diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 9087a8210c..088d30c85d 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -30,7 +30,7 @@ - [GetMetaData v3](#getmetadata-v3) - [The discovery domain: discv5](#the-discovery-domain-discv5) - [ENR structure](#enr-structure) - - [Custody subnet count](#custody-subnet-count) + - [Custody group count](#custody-group-count) @@ -49,6 +49,7 @@ | Name | Value | Description | |------------------------------------------------|------------------------------------------------|---------------------------------------------------------------------------| +| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `128` | The number of data column sidecar subnets used in the gossipsub protocol | | `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | | `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | @@ -318,10 +319,10 @@ Requests the MetaData of a peer, using the new `MetaData` definition given above #### ENR structure -##### Custody subnet count +##### Custody group count -A new field is added to the ENR under the key `csc` to facilitate custody data column discovery. +A new field is added to the ENR under the key `cgc` to facilitate custody data column discovery. | Key | Value | |--------|------------------------------------------| -| `csc` | Custody subnet count, `uint64` big endian integer with no leading zero bytes (`0` is encoded as empty byte string) | +| `cgc` | Custody group count, `uint64` big endian integer with no leading zero bytes (`0` is encoded as empty byte string) | diff --git a/specs/_features/eip7594/peer-sampling.md b/specs/_features/eip7594/peer-sampling.md index 5da03cb71a..ea0dd80b81 100644 --- a/specs/_features/eip7594/peer-sampling.md +++ b/specs/_features/eip7594/peer-sampling.md @@ -97,7 +97,7 @@ For reference, the table below shows the number of samples and the number of all A node SHOULD maintain a diverse set of peers for each column and each slot by verifying responsiveness to sample queries. -A node SHOULD query for samples from selected peers via `DataColumnSidecarsByRoot` request. A node utilizes `get_custody_columns` helper to determine which peer(s) it could request from, identifying a list of candidate peers for each selected column. +A node SHOULD query for samples from selected peers via `DataColumnSidecarsByRoot` request. A node utilizes `get_custody_groups` helper to determine which peer(s) it could request from, identifying a list of candidate peers for each selected column. If more than one candidate peer is found for a given column, a node SHOULD randomize its peer selection to distribute sample query load in the network. Nodes MAY use peer scoring to tune this selection (for example, by using weighted selection or by using a cut-off threshold). If possible, it is also recommended to avoid requesting many columns from the same peer in order to avoid relying on and exposing the sample selection to a single peer. @@ -115,4 +115,4 @@ A DAS provider is a consistently-available-for-DAS-queries, super-full (or high DAS providers can also be found out-of-band and configured into a node to connect to directly and prioritize. Nodes can add some set of these to their local configuration for persistent connection to bolster their DAS quality of service. -Such direct peering utilizes a feature supported out of the box today on all nodes and can complement (and reduce attackability and increase quality-of-service) alternative peer discovery mechanisms. \ No newline at end of file +Such direct peering utilizes a feature supported out of the box today on all nodes and can complement (and reduce attackability and increase quality-of-service) alternative peer discovery mechanisms. diff --git a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py index 3e1013734d..97cc948db5 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py @@ -7,21 +7,26 @@ ) -def _run_get_custody_columns(spec, rng, node_id=None, custody_subnet_count=None): +def _run_get_custody_columns(spec, rng, node_id=None, custody_group_count=None): if node_id is None: node_id = rng.randint(0, 2**256 - 1) - if custody_subnet_count is None: - custody_subnet_count = rng.randint(0, spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT) + if custody_group_count is None: + custody_group_count = rng.randint(0, spec.config.NUMBER_OF_CUSTODY_GROUPS) - result = spec.get_custody_columns(node_id, custody_subnet_count) + columns_per_group = spec.config.NUMBER_OF_COLUMNS // spec.config.NUMBER_OF_CUSTODY_GROUPS + groups = spec.get_custody_groups(node_id, custody_group_count) yield 'node_id', 'meta', node_id - yield 'custody_subnet_count', 'meta', int(custody_subnet_count) + yield 'custody_group_count', 'meta', int(custody_group_count) + + result = [] + for group in groups: + group_columns = spec.compute_columns_for_custody_group(group) + assert len(group_columns) == columns_per_group + result.extend(group_columns) assert len(result) == len(set(result)) - assert len(result) == ( - custody_subnet_count * spec.config.NUMBER_OF_COLUMNS // spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT - ) + assert len(result) == custody_group_count * columns_per_group assert all(i < spec.config.NUMBER_OF_COLUMNS for i in result) python_list_result = [int(i) for i in result] @@ -31,48 +36,48 @@ def _run_get_custody_columns(spec, rng, node_id=None, custody_subnet_count=None) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns__min_node_id_min_custody_subnet_count(spec): +def test_get_custody_columns__min_node_id_min_custody_group_count(spec): rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=0, custody_subnet_count=0) + yield from _run_get_custody_columns(spec, rng, node_id=0, custody_group_count=0) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns__min_node_id_max_custody_subnet_count(spec): +def test_get_custody_columns__min_node_id_max_custody_group_count(spec): rng = random.Random(1111) yield from _run_get_custody_columns( spec, rng, node_id=0, - custody_subnet_count=spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT) + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns__max_node_id_min_custody_subnet_count(spec): +def test_get_custody_columns__max_node_id_min_custody_group_count(spec): rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=2**256 - 1, custody_subnet_count=0) + yield from _run_get_custody_columns(spec, rng, node_id=2**256 - 1, custody_group_count=0) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns__max_node_id_max_custody_subnet_count(spec): +def test_get_custody_columns__max_node_id_max_custody_group_count(spec): rng = random.Random(1111) yield from _run_get_custody_columns( spec, rng, node_id=2**256 - 1, - custody_subnet_count=spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT, + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, ) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns__max_node_id_max_custody_subnet_count_minus_1(spec): +def test_get_custody_columns__max_node_id_max_custody_group_count_minus_1(spec): rng = random.Random(1111) yield from _run_get_custody_columns( spec, rng, node_id=2**256 - 2, - custody_subnet_count=spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT, + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, ) @@ -81,7 +86,7 @@ def test_get_custody_columns__max_node_id_max_custody_subnet_count_minus_1(spec) @single_phase def test_get_custody_columns__short_node_id(spec): rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=1048576, custody_subnet_count=1) + yield from _run_get_custody_columns(spec, rng, node_id=1048576, custody_group_count=1) @with_eip7594_and_later diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py index 5db3635a8e..7e7cef3421 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py @@ -6,13 +6,19 @@ ) -def run_get_custody_columns(spec, peer_count, custody_subnet_count): - assignments = [spec.get_custody_columns(node_id, custody_subnet_count) for node_id in range(peer_count)] +def run_get_custody_columns(spec, peer_count, custody_group_count): + assignments = [spec.get_custody_groups(node_id, custody_group_count) for node_id in range(peer_count)] - columns_per_subnet = spec.config.NUMBER_OF_COLUMNS // spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT + columns_per_group = spec.config.NUMBER_OF_COLUMNS // spec.config.NUMBER_OF_CUSTODY_GROUPS for assignment in assignments: - assert len(assignment) == custody_subnet_count * columns_per_subnet - assert len(assignment) == len(set(assignment)) + columns = [] + for group in assignment: + group_columns = spec.compute_columns_for_custody_group(group) + assert len(group_columns) == columns_per_group + columns.extend(group_columns) + + assert len(columns) == custody_group_count * columns_per_group + assert len(columns) == len(set(columns)) @with_eip7594_and_later @@ -20,9 +26,9 @@ def run_get_custody_columns(spec, peer_count, custody_subnet_count): @single_phase def test_get_custody_columns_peers_within_number_of_columns(spec): peer_count = 10 - custody_subnet_count = spec.config.CUSTODY_REQUIREMENT + custody_group_count = spec.config.CUSTODY_REQUIREMENT assert spec.config.NUMBER_OF_COLUMNS > peer_count - run_get_custody_columns(spec, peer_count, custody_subnet_count) + run_get_custody_columns(spec, peer_count, custody_group_count) @with_eip7594_and_later @@ -30,24 +36,31 @@ def test_get_custody_columns_peers_within_number_of_columns(spec): @single_phase def test_get_custody_columns_peers_more_than_number_of_columns(spec): peer_count = 200 - custody_subnet_count = spec.config.CUSTODY_REQUIREMENT + custody_group_count = spec.config.CUSTODY_REQUIREMENT assert spec.config.NUMBER_OF_COLUMNS < peer_count - run_get_custody_columns(spec, peer_count, custody_subnet_count) + run_get_custody_columns(spec, peer_count, custody_group_count) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns_maximum_subnets(spec): +def test_get_custody_columns_maximum_groups(spec): peer_count = 10 - custody_subnet_count = spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT - run_get_custody_columns(spec, peer_count, custody_subnet_count) + custody_group_count = spec.config.NUMBER_OF_CUSTODY_GROUPS + run_get_custody_columns(spec, peer_count, custody_group_count) @with_eip7594_and_later @spec_test @single_phase -def test_get_custody_columns_custody_size_more_than_number_of_columns(spec): +def test_get_custody_columns_custody_size_more_than_number_of_groups(spec): node_id = 1 - custody_subnet_count = spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT + 1 - expect_assertion_error(lambda: spec.get_custody_columns(node_id, custody_subnet_count)) + custody_group_count = spec.config.NUMBER_OF_CUSTODY_GROUPS + 1 + expect_assertion_error(lambda: spec.get_custody_groups(node_id, custody_group_count)) + + +@with_eip7594_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group_out_of_bound_custody_group(spec): + expect_assertion_error(lambda: spec.compute_columns_for_custody_group(spec.config.NUMBER_OF_CUSTODY_GROUPS)) diff --git a/tests/formats/networking/README.md b/tests/formats/networking/README.md index e4679c17eb..57effda266 100644 --- a/tests/formats/networking/README.md +++ b/tests/formats/networking/README.md @@ -3,4 +3,5 @@ The aim of the networking tests is to set a base-line on what really needs to pass, i.e. the essentials. Handlers: -- [`get_custody_columns`](./get_custody_columns.md): `get_custody_columns` helper tests +- [`compute_columns_for_custody_group`](./compute_columns_for_custody_group.md): `compute_columns_for_custody_group` helper tests +- [`get_custody_groups`](./get_custody_groups.md): `get_custody_groups` helper tests diff --git a/tests/formats/networking/compute_columns_for_custody_group.md b/tests/formats/networking/compute_columns_for_custody_group.md new file mode 100644 index 0000000000..23e96025de --- /dev/null +++ b/tests/formats/networking/compute_columns_for_custody_group.md @@ -0,0 +1,13 @@ +# `compute_columns_for_custody_group` tests + +`compute_columns_for_custody_group` tests provide sanity checks for the correctness of the `compute_columns_for_custody_group` helper function. + +## Test case format + +### `meta.yaml` + +```yaml +description: string -- optional: description of test case, purely for debugging purposes. +custody_group: int -- argument: the custody group index. +result: list of int -- output: the list of resulting column indices. +``` diff --git a/tests/formats/networking/get_custody_columns.md b/tests/formats/networking/get_custody_groups.md similarity index 53% rename from tests/formats/networking/get_custody_columns.md rename to tests/formats/networking/get_custody_groups.md index ee0c30859c..46206da85d 100644 --- a/tests/formats/networking/get_custody_columns.md +++ b/tests/formats/networking/get_custody_groups.md @@ -1,6 +1,6 @@ -# `get_custody_columns` tests +# `get_custody_groups` tests -`get_custody_columns` tests provide sanity check of the correctness of `get_custody_columns` helper. +`get_custody_groups` tests provide sanity checks for the correctness of the `get_custody_groups` helper function. ## Test case format @@ -9,6 +9,6 @@ ```yaml description: string -- optional: description of test case, purely for debugging purposes. node_id: int -- argument: the NodeID input. -custody_subnet_count: int -- argument: the count of custody subnets. -result: list of int -- output: the list of resulting column indices. +custody_group_count: int -- argument: the count of custody groups. +result: list of int -- output: the list of resulting custody group indices. ``` diff --git a/tests/generators/networking/main.py b/tests/generators/networking/main.py index 2681daf68b..25a6c06ece 100644 --- a/tests/generators/networking/main.py +++ b/tests/generators/networking/main.py @@ -5,7 +5,8 @@ if __name__ == "__main__": eip7594_mods = {key: 'eth2spec.test.eip7594.networking.test_' + key for key in [ - 'get_custody_columns', + 'compute_columns_for_custody_group', + 'get_custody_groups', ]} all_mods = { EIP7594: eip7594_mods From 68d32accf945a84f69d4c779cb6c71223a311eac Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 11 Oct 2024 07:54:50 -0500 Subject: [PATCH 008/141] Delete trailing whitespace for markdown files --- configs/README.md | 4 +- docs/docs/templates/beacon-chain-template.md | 4 +- specs/_features/custody_game/beacon-chain.md | 6 +- specs/_features/das/p2p-interface.md | 16 ++-- specs/_features/eip7594/fork-choice.md | 8 +- specs/_features/eip7594/peer-sampling.md | 2 +- specs/_features/eip7732/beacon-chain.md | 66 +++++++------- specs/_features/eip7732/builder.md | 28 +++--- specs/_features/eip7732/fork-choice.md | 68 +++++++-------- specs/_features/eip7732/fork.md | 2 +- specs/_features/eip7732/p2p-interface.md | 38 ++++---- specs/_features/eip7732/validator.md | 44 +++++----- specs/_features/sharding/beacon-chain.md | 12 +-- .../sharding/polynomial-commitments.md | 10 +-- specs/_features/whisk/beacon-chain.md | 4 +- specs/bellatrix/p2p-interface.md | 2 +- specs/capella/validator.md | 2 +- specs/deneb/polynomial-commitments.md | 2 +- specs/electra/beacon-chain.md | 2 +- specs/phase0/weak-subjectivity.md | 6 +- ssz/merkle-proofs.md | 2 +- sync/optimistic.md | 2 +- tests/README.md | 86 +++++++++---------- tests/core/pyspec/eth2spec/config/README.md | 4 +- .../pyspec/eth2spec/gen_helpers/README.md | 8 +- tests/formats/README.md | 16 ++-- tests/formats/epoch_processing/README.md | 2 +- tests/formats/fork_choice/README.md | 2 +- tests/formats/rewards/README.md | 2 +- tests/formats/shuffling/README.md | 2 +- tests/formats/ssz_generic/README.md | 2 +- tests/formats/ssz_static/core.md | 2 +- tests/generators/README.md | 8 +- tests/generators/epoch_processing/README.md | 2 +- tests/generators/operations/README.md | 2 +- tests/generators/sanity/README.md | 2 +- 36 files changed, 235 insertions(+), 235 deletions(-) diff --git a/configs/README.md b/configs/README.md index 6ef081e4c4..beb04a11f6 100644 --- a/configs/README.md +++ b/configs/README.md @@ -1,7 +1,7 @@ # Configurations This directory contains a set of configurations used for testing, testnets, and mainnet. -A client binary may be compiled for a specific `PRESET_BASE`, +A client binary may be compiled for a specific `PRESET_BASE`, and then load different configurations around that preset to participate in different networks or tests. Standard configs: @@ -24,7 +24,7 @@ In this case, the suffix on the new variable may be removed, and the old variabl A previous iteration of forking made use of "timelines", but this collides with the definitions used in the spec (variables for special forking slots, etc.), and was not integrated sufficiently in any of the spec tools or implementations. Instead, the config essentially doubles as fork definition now, e.g. changing the value for `ALTAIR_FORK_EPOCH` changes the fork. - + ## Format Each preset and configuration is a key-value mapping. diff --git a/docs/docs/templates/beacon-chain-template.md b/docs/docs/templates/beacon-chain-template.md index 4d22d3908e..60bde9f666 100644 --- a/docs/docs/templates/beacon-chain-template.md +++ b/docs/docs/templates/beacon-chain-template.md @@ -67,9 +67,9 @@ class CONTAINER_NAME(Container): ### Block processing - - + + ## Testing *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure testing only. diff --git a/specs/_features/custody_game/beacon-chain.md b/specs/_features/custody_game/beacon-chain.md index e4effa2e17..092846a484 100644 --- a/specs/_features/custody_game/beacon-chain.md +++ b/specs/_features/custody_game/beacon-chain.md @@ -573,7 +573,7 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed # Any signed custody-slashing should result in at least one slashing. # If the custody bits are valid, then the claim itself is slashed. - malefactor = state.validators[custody_slashing.malefactor_index] + malefactor = state.validators[custody_slashing.malefactor_index] whistleblower = state.validators[custody_slashing.whistleblower_index] domain = get_domain(state, DOMAIN_CUSTODY_BIT_SLASHING, get_current_epoch(state)) signing_root = compute_signing_root(custody_slashing, domain) @@ -596,7 +596,7 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed # Verify existence and participation of claimed malefactor attesters = get_attesting_indices(state, attestation) assert custody_slashing.malefactor_index in attesters - + # Verify the malefactor custody key epoch_to_sign = get_randao_epoch_for_custody_period( get_custody_period_for_validator(custody_slashing.malefactor_index, attestation.data.target.epoch), @@ -619,7 +619,7 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed for attester_index in attesters: if attester_index != custody_slashing.malefactor_index: increase_balance(state, attester_index, whistleblower_reward) - # No special whisteblower reward: it is expected to be an attester. Others are free to slash too however. + # No special whisteblower reward: it is expected to be an attester. Others are free to slash too however. else: # The claim was false, the custody bit was correct. Slash the whistleblower that induced this work. slash_validator(state, custody_slashing.whistleblower_index) diff --git a/specs/_features/das/p2p-interface.md b/specs/_features/das/p2p-interface.md index b166c9c3e4..6372c481e1 100644 --- a/specs/_features/das/p2p-interface.md +++ b/specs/_features/das/p2p-interface.md @@ -33,7 +33,7 @@ ## Introduction For an introduction about DAS itself, see [the DAS participation spec](sampling.md#data-availability-sampling). -This is not a pre-requisite for the network layer, but will give you valuable context. +This is not a pre-requisite for the network layer, but will give you valuable context. For sampling, all nodes need to query for `k` random samples each slot. @@ -55,13 +55,13 @@ The push model does not aim to serve "historical" queries (anything older than t Historical queries are still required for the unhappy case, where messages are not pushed quick enough, and missing samples are not reconstructed by other nodes on the horizontal subnet quick enough. -The main challenge in supporting historical queries is to target the right nodes, +The main challenge in supporting historical queries is to target the right nodes, without concentrating too many requests on a single node, or breaking the network/consensus identity separation. ## DAS Subnets On a high level, the push-model roles are divided into: -- Sources: create blobs of shard block data, and transformed into many tiny samples. +- Sources: create blobs of shard block data, and transformed into many tiny samples. - Sinks: continuously look for samples At full operation, the network has one proposer, per shard, per slot. @@ -93,15 +93,15 @@ Peers on the horizontal subnet are expected to at least perform regular propagat Nodes on this same subnet can replicate the sampling efficiently (including a proof for each sample), and distribute it to any vertical networks that are available to them. -Since the messages are content-addressed (instead of origin-stamped), -multiple publishers of the same samples on a vertical subnet do not hurt performance, +Since the messages are content-addressed (instead of origin-stamped), +multiple publishers of the same samples on a vertical subnet do not hurt performance, but actually improve it by shortcutting regular propagation on the vertical subnet, and thus lowering the latency to a sample. ### Vertical subnets Vertical subnets propagate the samples to every peer that is interested. -These interests are randomly sampled and rotate quickly: although not perfect, +These interests are randomly sampled and rotate quickly: although not perfect, sufficient to avoid any significant amount of nodes from being 100% predictable. As soon as a sample is missing after the expected propagation time window, @@ -166,7 +166,7 @@ The [DAS participation spec](sampling.md#horizontal-subnets) outlines when and w #### Vertical subnets: `das_sample_{subnet_index}` -Shard blob samples can be verified with just a 48 byte KZG proof (commitment quotient polynomial), +Shard blob samples can be verified with just a 48 byte KZG proof (commitment quotient polynomial), against the commitment to blob polynomial, specific to that `(shard, slot)` key. The following validations MUST pass before forwarding the `sample` on the vertical subnet. @@ -192,7 +192,7 @@ This is to serve other peers that may have missed it. To pull samples from nodes, in case of network instability when samples are unavailable, a new query method is added to the Req-Resp domain. -This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md). +This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md). Note that DAS networking uses a different protocol prefix: `/eth2/das/req` diff --git a/specs/_features/eip7594/fork-choice.md b/specs/_features/eip7594/fork-choice.md index f406b7472a..ed91ab1d46 100644 --- a/specs/_features/eip7594/fork-choice.md +++ b/specs/_features/eip7594/fork-choice.md @@ -25,10 +25,10 @@ This is the modification of the fork choice accompanying EIP-7594. ```python def is_data_available(beacon_block_root: Root) -> bool: # `retrieve_column_sidecars` is implementation and context dependent, replacing - # `retrieve_blobs_and_proofs`. For the given block root, it returns all column - # sidecars to sample, or raises an exception if they are not available. - # The p2p network does not guarantee sidecar retrieval outside of - # `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` epochs. + # `retrieve_blobs_and_proofs`. For the given block root, it returns all column + # sidecars to sample, or raises an exception if they are not available. + # The p2p network does not guarantee sidecar retrieval outside of + # `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` epochs. column_sidecars = retrieve_column_sidecars(beacon_block_root) return all( verify_data_column_sidecar(column_sidecar) diff --git a/specs/_features/eip7594/peer-sampling.md b/specs/_features/eip7594/peer-sampling.md index 5da03cb71a..8b90c93aa2 100644 --- a/specs/_features/eip7594/peer-sampling.md +++ b/specs/_features/eip7594/peer-sampling.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Peer Sampling +# EIP-7594 -- Peer Sampling **Notice**: This document is a work-in-progress for researchers and implementers. diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 30651cedbe..2303e33d40 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -61,34 +61,34 @@ ## Introduction -This is the beacon chain specification of the enshrined proposer builder separation feature. +This is the beacon chain specification of the enshrined proposer builder separation feature. *Note:* This specification is built upon [Electra](../../electra/beacon-chain.md) and is under active development. This feature adds new staked consensus participants called *Builders* and new honest validators duties called *payload timeliness attestations*. The slot is divided in **four** intervals. Honest validators gather *signed bids* (a `SignedExecutionPayloadHeader`) from builders and submit their consensus blocks (a `SignedBeaconBlock`) including these bids at the beginning of the slot. At the start of the second interval, honest validators submit attestations just as they do previous to this feature). At the start of the third interval, aggregators aggregate these attestations and the builder broadcasts either a full payload or a message indicating that they are withholding the payload (a `SignedExecutionPayloadEnvelope`). At the start of the fourth interval, some validators selected to be members of the new **Payload Timeliness Committee** (PTC) attest to the presence and timeliness of the builder's payload. -At any given slot, the status of the blockchain's head may be either -- A block from a previous slot (e.g. the current slot's proposer did not submit its block). -- An *empty* block from the current slot (e.g. the proposer submitted a timely block, but the builder did not reveal the payload on time). -- A full block for the current slot (both the proposer and the builder revealed on time). +At any given slot, the status of the blockchain's head may be either +- A block from a previous slot (e.g. the current slot's proposer did not submit its block). +- An *empty* block from the current slot (e.g. the proposer submitted a timely block, but the builder did not reveal the payload on time). +- A full block for the current slot (both the proposer and the builder revealed on time). ## Constants ### Payload status -| Name | Value | -| - | - | +| Name | Value | +| - | - | | `PAYLOAD_ABSENT` | `uint8(0)` | -| `PAYLOAD_PRESENT` | `uint8(1)` | -| `PAYLOAD_WITHHELD` | `uint8(2)` | +| `PAYLOAD_PRESENT` | `uint8(1)` | +| `PAYLOAD_WITHHELD` | `uint8(2)` | | `PAYLOAD_INVALID_STATUS` | `uint8(3)` | ## Preset ### Misc -| Name | Value | -| - | - | +| Name | Value | +| - | - | | `PTC_SIZE` | `uint64(2**9)` (=512) # (New in EIP-7732) | ### Domain types @@ -151,7 +151,7 @@ class SignedExecutionPayloadHeader(Container): message: ExecutionPayloadHeader signature: BLSSignature ``` - + #### `ExecutionPayloadEnvelope` ```python @@ -177,7 +177,7 @@ class SignedExecutionPayloadEnvelope(Container): #### `BeaconBlockBody` -**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly. The field `execution_requests` is removed from the beacon block body and moved into the signed execution payload envelope. +**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly. The field `execution_requests` is removed from the beacon block body and moved into the signed execution payload envelope. ```python class BeaconBlockBody(Container): @@ -203,7 +203,7 @@ class BeaconBlockBody(Container): #### `ExecutionPayloadHeader` -**Note:** The `ExecutionPayloadHeader` is modified to only contain the block hash of the committed `ExecutionPayload` in addition to the builder's payment information, gas limit and KZG commitments root to verify the inclusion proofs. +**Note:** The `ExecutionPayloadHeader` is modified to only contain the block hash of the committed `ExecutionPayload` in addition to the builder's payment information, gas limit and KZG commitments root to verify the inclusion proofs. ```python class ExecutionPayloadHeader(Container): @@ -219,7 +219,7 @@ class ExecutionPayloadHeader(Container): #### `BeaconState` -*Note*: The `BeaconState` is modified to track the last withdrawals honored in the CL. The `latest_execution_payload_header` is modified semantically to refer not to a past committed `ExecutionPayload` but instead it corresponds to the state's slot builder's bid. Another addition is to track the last committed block hash and the last slot that was full, that is in which there were both consensus and execution blocks included. +*Note*: The `BeaconState` is modified to track the last withdrawals honored in the CL. The `latest_execution_payload_header` is modified semantically to refer not to a past committed `ExecutionPayload` but instead it corresponds to the state's slot builder's bid. Another addition is to track the last committed block hash and the last slot that was full, that is in which there were both consensus and execution blocks included. ```python class BeaconState(Container): @@ -311,7 +311,7 @@ def remove_flag(flags: ParticipationFlags, flag_index: int) -> ParticipationFlag ```python def is_valid_indexed_payload_attestation( - state: BeaconState, + state: BeaconState, indexed_payload_attestation: IndexedPayloadAttestation) -> bool: """ Check if ``indexed_payload_attestation`` is not empty, has sorted and unique indices and has @@ -335,7 +335,7 @@ def is_valid_indexed_payload_attestation( #### `is_parent_block_full` -This function returns true if the last committed payload header was fulfilled with a payload, this can only happen when both beacon block and payload were present. This function must be called on a beacon state before processing the execution payload header in the block. +This function returns true if the last committed payload header was fulfilled with a payload, this can only happen when both beacon block and payload were present. This function must be called on a beacon state before processing the execution payload header in the block. ```python def is_parent_block_full(state: BeaconState) -> bool: @@ -354,8 +354,8 @@ def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]: epoch = compute_epoch_at_slot(slot) committees_per_slot = bit_floor(min(get_committee_count_per_slot(state, epoch), PTC_SIZE)) members_per_committee = PTC_SIZE // committees_per_slot - - validator_indices: List[ValidatorIndex] = [] + + validator_indices: List[ValidatorIndex] = [] for idx in range(committees_per_slot): beacon_committee = get_beacon_committee(state, slot, CommitteeIndex(idx)) validator_indices += beacon_committee[:members_per_committee] @@ -390,7 +390,7 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V #### `get_payload_attesting_indices` ```python -def get_payload_attesting_indices(state: BeaconState, slot: Slot, +def get_payload_attesting_indices(state: BeaconState, slot: Slot, payload_attestation: PayloadAttestation) -> Set[ValidatorIndex]: """ Return the set of attesting indices corresponding to ``payload_attestation``. @@ -402,7 +402,7 @@ def get_payload_attesting_indices(state: BeaconState, slot: Slot, #### `get_indexed_payload_attestation` ```python -def get_indexed_payload_attestation(state: BeaconState, slot: Slot, +def get_indexed_payload_attestation(state: BeaconState, slot: Slot, payload_attestation: PayloadAttestation) -> IndexedPayloadAttestation: """ Return the indexed payload attestation corresponding to ``payload_attestation``. @@ -442,7 +442,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: ##### Modified `process_withdrawals` -**Note:** This is modified to take only the `state` as parameter. Withdrawals are deterministic given the beacon state, any execution payload that has the corresponding block as parent beacon block is required to honor these withdrawals in the execution layer. This function must be called before `process_execution_payload_header` as this latter function affects validator balances. +**Note:** This is modified to take only the `state` as parameter. Withdrawals are deterministic given the beacon state, any execution payload that has the corresponding block as parent beacon block is required to honor these withdrawals in the execution layer. This function must be called before `process_execution_payload_header` as this latter function affects validator balances. ```python def process_withdrawals(state: BeaconState) -> None: @@ -481,7 +481,7 @@ def process_withdrawals(state: BeaconState) -> None: ##### New `verify_execution_payload_header_signature` ```python -def verify_execution_payload_header_signature(state: BeaconState, +def verify_execution_payload_header_signature(state: BeaconState, signed_header: SignedExecutionPayloadHeader) -> bool: # Check the signature builder = state.validators[signed_header.message.builder_index] @@ -516,7 +516,7 @@ def process_execution_payload_header(state: BeaconState, block: BeaconBlock) -> decrease_balance(state, builder_index, amount) increase_balance(state, block.proposer_index, amount) - # Cache the signed execution payload header + # Cache the signed execution payload header state.latest_execution_payload_header = header ``` @@ -557,7 +557,7 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload data = payload_attestation.data assert data.beacon_block_root == state.latest_block_header.parent_root # Check that the attestation is for the previous slot - assert data.slot + 1 == state.slot + assert data.slot + 1 == state.slot # Verify signature indexed_payload_attestation = get_indexed_payload_attestation(state, data.slot, payload_attestation) @@ -658,11 +658,11 @@ def verify_execution_payload_envelope_signature( *Note*: `process_execution_payload` is now an independent check in state transition. It is called when importing a signed execution payload proposed by the builder of the current slot. ```python -def process_execution_payload(state: BeaconState, - signed_envelope: SignedExecutionPayloadEnvelope, +def process_execution_payload(state: BeaconState, + signed_envelope: SignedExecutionPayloadEnvelope, execution_engine: ExecutionEngine, verify: bool = True) -> None: # Verify signature - if verify: + if verify: assert verify_execution_payload_envelope_signature(state, signed_envelope) envelope = signed_envelope.message payload = envelope.payload @@ -670,7 +670,7 @@ def process_execution_payload(state: BeaconState, previous_state_root = hash_tree_root(state) if state.latest_block_header.state_root == Root(): state.latest_block_header.state_root = previous_state_root - + # Verify consistency with the beacon block assert envelope.beacon_block_root == hash_tree_root(state.latest_block_header) @@ -679,14 +679,14 @@ def process_execution_payload(state: BeaconState, assert envelope.builder_index == committed_header.builder_index assert committed_header.blob_kzg_commitments_root == hash_tree_root(envelope.blob_kzg_commitments) - if not envelope.payload_withheld: + if not envelope.payload_withheld: # Verify the withdrawals root assert hash_tree_root(payload.withdrawals) == state.latest_withdrawals_root # Verify the gas_limit assert committed_header.gas_limit == payload.gas_limit - assert committed_header.block_hash == payload.block_hash + assert committed_header.block_hash == payload.block_hash # Verify consistency of the parent hash with respect to the previous execution payload assert payload.parent_hash == state.latest_block_hash # Verify prev_randao @@ -696,7 +696,7 @@ def process_execution_payload(state: BeaconState, # Verify commitments are under limit assert len(envelope.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK # Verify the execution payload is valid - versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) + versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in envelope.blob_kzg_commitments] requests = envelope.execution_requests assert execution_engine.verify_and_notify_new_payload( @@ -722,6 +722,6 @@ def process_execution_payload(state: BeaconState, state.latest_full_slot = state.slot # Verify the state root - if verify: + if verify: assert envelope.state_root == hash_tree_root(state) ``` diff --git a/specs/_features/eip7732/builder.md b/specs/_features/eip7732/builder.md index 491f625d89..7c793b07e6 100644 --- a/specs/_features/eip7732/builder.md +++ b/specs/_features/eip7732/builder.md @@ -16,20 +16,20 @@ This is an accompanying document which describes the expected actions of a "buil ## Introduction -With the EIP-7732 Fork, the protocol includes new staked participants of the protocol called *Builders*. While Builders are a subset of the validator set, they have extra attributions that are optional. Validators may opt to not be builders and as such we collect the set of guidelines for those validators that want to act as builders in this document. +With the EIP-7732 Fork, the protocol includes new staked participants of the protocol called *Builders*. While Builders are a subset of the validator set, they have extra attributions that are optional. Validators may opt to not be builders and as such we collect the set of guidelines for those validators that want to act as builders in this document. ## Builders attributions -Builders can submit bids to produce execution payloads. They can broadcast these bids in the form of `SignedExecutionPayloadHeader` objects, these objects encode a commitment to reveal an execution payload in exchange for a payment. When their bids are chosen by the corresponding proposer, builders are expected to broadcast an accompanying `SignedExecutionPayloadEnvelope` object honoring the commitment. +Builders can submit bids to produce execution payloads. They can broadcast these bids in the form of `SignedExecutionPayloadHeader` objects, these objects encode a commitment to reveal an execution payload in exchange for a payment. When their bids are chosen by the corresponding proposer, builders are expected to broadcast an accompanying `SignedExecutionPayloadEnvelope` object honoring the commitment. -Thus, builders tasks are divided in two, submitting bids, and submitting payloads. +Thus, builders tasks are divided in two, submitting bids, and submitting payloads. ### Constructing the payload bid -Builders can broadcast a payload bid for the current or the next slot's proposer to include. They produce a `SignedExecutionPayloadHeader` as follows. +Builders can broadcast a payload bid for the current or the next slot's proposer to include. They produce a `SignedExecutionPayloadHeader` as follows. 1. Set `header.parent_block_hash` to the current head of the execution chain (this can be obtained from the beacon state as `state.last_block_hash`). -2. Set `header.parent_block_root` to be the head of the consensus chain (this can be obtained from the beacon state as `hash_tree_root(state.latest_block_header)`. The `parent_block_root` and `parent_block_hash` must be compatible, in the sense that they both should come from the same `state` by the method described in this and the previous point. +2. Set `header.parent_block_root` to be the head of the consensus chain (this can be obtained from the beacon state as `hash_tree_root(state.latest_block_header)`. The `parent_block_root` and `parent_block_hash` must be compatible, in the sense that they both should come from the same `state` by the method described in this and the previous point. 3. Construct an execution payload. This can be performed with an external execution engine with a call to `engine_getPayloadV4`. 4. Set `header.block_hash` to be the block hash of the constructed payload, that is `payload.block_hash`. 5. Set `header.gas_limit` to be the gas limit of the constructed payload, that is `payload.gas_limit`. @@ -48,13 +48,13 @@ def get_execution_payload_header_signature( return bls.Sign(privkey, signing_root) ``` -The builder assembles then `signed_execution_payload_header = SignedExecutionPayloadHeader(message=header, signature=signature)` and broadcasts it on the `execution_payload_header` global gossip topic. +The builder assembles then `signed_execution_payload_header = SignedExecutionPayloadHeader(message=header, signature=signature)` and broadcasts it on the `execution_payload_header` global gossip topic. ### Constructing the `BlobSidecar`s [Modified in EIP-7732] -The `BlobSidecar` container is modified indirectly because the constant `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` is modified. The function `get_blob_sidecars` is modified because the KZG commitments are no longer included in the beacon block but rather in the `ExecutionPayloadEnvelope`, the builder has to send the commitments as parameters to this function. +The `BlobSidecar` container is modified indirectly because the constant `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` is modified. The function `get_blob_sidecars` is modified because the KZG commitments are no longer included in the beacon block but rather in the `ExecutionPayloadEnvelope`, the builder has to send the commitments as parameters to this function. ```python def get_blob_sidecars(signed_block: SignedBeaconBlock, @@ -100,19 +100,19 @@ def get_blob_sidecars(signed_block: SignedBeaconBlock, ### Constructing the execution payload envelope -When the proposer publishes a valid `SignedBeaconBlock` containing a signed commitment by the builder, the builder is later expected to broadcast the corresponding `SignedExecutionPayloadEnvelope` that fulfills this commitment. See below for a special case of an *honestly withheld payload*. +When the proposer publishes a valid `SignedBeaconBlock` containing a signed commitment by the builder, the builder is later expected to broadcast the corresponding `SignedExecutionPayloadEnvelope` that fulfills this commitment. See below for a special case of an *honestly withheld payload*. -To construct the `execution_payload_envelope` the builder must perform the following steps, we alias `header` to be the committed `ExecutionPayloadHeader` in the beacon block. +To construct the `execution_payload_envelope` the builder must perform the following steps, we alias `header` to be the committed `ExecutionPayloadHeader` in the beacon block. -1. Set the `payload` field to be the `ExecutionPayload` constructed when creating the corresponding bid. This payload **MUST** have the same block hash as `header.block_hash`. -2. Set the `builder_index` field to be the validator index of the builder performing these steps. This field **MUST** be `header.builder_index`. +1. Set the `payload` field to be the `ExecutionPayload` constructed when creating the corresponding bid. This payload **MUST** have the same block hash as `header.block_hash`. +2. Set the `builder_index` field to be the validator index of the builder performing these steps. This field **MUST** be `header.builder_index`. 3. Set `beacon_block_root` to be the `hash_tree_root` of the corresponding beacon block. 4. Set `blob_kzg_commitments` to be the `commitments` field of the blobs bundle constructed when constructing the bid. This field **MUST** have a `hash_tree_root` equal to `header.blob_kzg_commitments_root`. 5. Set `payload_witheld` to `False`. After setting these parameters, the builder should run `process_execution_payload(state, signed_envelope, verify=False)` and this function should not trigger an exception. -6. Set `state_root` to `hash_tree_root(state)`. +6. Set `state_root` to `hash_tree_root(state)`. After preparing the `envelope` the builder should sign the envelope using: ```python def get_execution_payload_envelope_signature( @@ -121,8 +121,8 @@ def get_execution_payload_envelope_signature( signing_root = compute_signing_root(envelope, domain) return bls.Sign(privkey, signing_root) ``` -The builder assembles then `signed_execution_payload_envelope = SignedExecutionPayloadEnvelope(message=envelope, signature=signature)` and broadcasts it on the `execution_payload` global gossip topic. +The builder assembles then `signed_execution_payload_envelope = SignedExecutionPayloadEnvelope(message=envelope, signature=signature)` and broadcasts it on the `execution_payload` global gossip topic. ### Honest payload withheld messages -An honest builder that has seen a `SignedBeaconBlock` referencing his signed bid, but that block was not timely and thus it is not the head of the builder's chain, may choose to withhold their execution payload. For this the builder should simply act as if it were building an empty payload, without any transactions, withdrawals, etc. The `payload.block_hash` may not be equal to `header.block_hash`. The builder may then sets `payload_withheld` to `True`. If the PTC sees this message and votes for it, validators will attribute a *withholding boost* to the builder, which would increase the forkchoice weight of the parent block, favoring it and preventing the builder from being charged for the bid by not revealing. +An honest builder that has seen a `SignedBeaconBlock` referencing his signed bid, but that block was not timely and thus it is not the head of the builder's chain, may choose to withhold their execution payload. For this the builder should simply act as if it were building an empty payload, without any transactions, withdrawals, etc. The `payload.block_hash` may not be equal to `header.block_hash`. The builder may then sets `payload_withheld` to `True`. If the PTC sees this message and votes for it, validators will attribute a *withholding boost* to the builder, which would increase the forkchoice weight of the parent block, favoring it and preventing the builder from being charged for the bid by not revealing. diff --git a/specs/_features/eip7732/fork-choice.md b/specs/_features/eip7732/fork-choice.md index 0eb49ddfc1..a52e959cba 100644 --- a/specs/_features/eip7732/fork-choice.md +++ b/specs/_features/eip7732/fork-choice.md @@ -44,15 +44,15 @@ This is the modification of the fork choice accompanying the EIP-7732 upgrade. | Name | Value | | -------------------- | ----------- | -| `PAYLOAD_TIMELY_THRESHOLD` | `PTC_SIZE / 2` (=`uint64(256)`) | +| `PAYLOAD_TIMELY_THRESHOLD` | `PTC_SIZE / 2` (=`uint64(256)`) | | `INTERVALS_PER_SLOT` | `4` # [modified in EIP-7732] | -| `PROPOSER_SCORE_BOOST` | `20` # [modified in EIP-7732] | -| `PAYLOAD_WITHHOLD_BOOST` | `40` | -| `PAYLOAD_REVEAL_BOOST` | `40` | +| `PROPOSER_SCORE_BOOST` | `20` # [modified in EIP-7732] | +| `PAYLOAD_WITHHOLD_BOOST` | `40` | +| `PAYLOAD_REVEAL_BOOST` | `40` | ## Containers -### New `ChildNode` +### New `ChildNode` Auxiliary class to consider `(block, slot, bool)` LMD voting ```python @@ -75,7 +75,7 @@ class LatestMessage(object): ``` ### Modified `update_latest_messages` -**Note:** the function `update_latest_messages` is updated to use the attestation slot instead of target. Notice that this function is only called on validated attestations and validators cannot attest twice in the same epoch without equivocating. Notice also that target epoch number and slot number are validated on `validate_on_attestation`. +**Note:** the function `update_latest_messages` is updated to use the attestation slot instead of target. Notice that this function is only called on validated attestations and validators cannot attest twice in the same epoch without equivocating. Notice also that target epoch number and slot number are validated on `validate_on_attestation`. ```python def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIndex], attestation: Attestation) -> None: @@ -87,8 +87,8 @@ def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIn store.latest_messages[i] = LatestMessage(slot=slot, root=beacon_block_root) ``` -### Modified `Store` -**Note:** `Store` is modified to track the intermediate states of "empty" consensus blocks, that is, those consensus blocks for which the corresponding execution payload has not been revealed or has not been included on chain. +### Modified `Store` +**Note:** `Store` is modified to track the intermediate states of "empty" consensus blocks, that is, those consensus blocks for which the corresponding execution payload has not been revealed or has not been included on chain. ```python @dataclass @@ -114,7 +114,7 @@ class Store(object): ptc_vote: Dict[Root, Vector[uint8, PTC_SIZE]] = field(default_factory=dict) # [New in EIP-7732] ``` -### Modified `get_forkchoice_store` +### Modified `get_forkchoice_store` ```python def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store: @@ -162,8 +162,8 @@ def notify_ptc_messages(store: Store, state: BeaconState, payload_attestations: store, PayloadAttestationMessage( validator_index=idx, - data=payload_attestation.data, - signature=BLSSignature(), + data=payload_attestation.data, + signature=BLSSignature(), is_from_block=True ) ) @@ -174,7 +174,7 @@ def notify_ptc_messages(store: Store, state: BeaconState, payload_attestations: ```python def is_payload_present(store: Store, beacon_block_root: Root) -> bool: """ - Return whether the execution payload for the beacon block with root ``beacon_block_root`` was voted as present + Return whether the execution payload for the beacon block with root ``beacon_block_root`` was voted as present by the PTC """ # The beacon block root must be known @@ -192,15 +192,15 @@ def is_parent_node_full(store: Store, block: BeaconBlock) -> bool: return parent_block_hash == message_block_hash ``` -### Modified `get_ancestor` -**Note:** `get_ancestor` is modified to return whether the chain is based on an *empty* or *full* block. +### Modified `get_ancestor` +**Note:** `get_ancestor` is modified to return whether the chain is based on an *empty* or *full* block. ```python def get_ancestor(store: Store, root: Root, slot: Slot) -> ChildNode: """ - Returns the beacon block root, the slot and the payload status of the ancestor of the beacon block - with ``root`` at ``slot``. If the beacon block with ``root`` is already at ``slot`` or we are - requesting an ancestor "in the future" it returns its PTC status instead of the actual payload content. + Returns the beacon block root, the slot and the payload status of the ancestor of the beacon block + with ``root`` at ``slot``. If the beacon block with ``root`` is already at ``slot`` or we are + requesting an ancestor "in the future" it returns its PTC status instead of the actual payload content. """ block = store.blocks[root] if block.slot <= slot: @@ -235,7 +235,7 @@ def is_supporting_vote(store: Store, node: ChildNode, message: LatestMessage) -> """ if node.root == message.root: # an attestation for a given root always counts for that root regardless if full or empty - # as long as the attestation happened after the requested slot. + # as long as the attestation happened after the requested slot. return node.slot <= message.slot message_block = store.blocks[message.root] if node.slot >= message_block.slot: @@ -245,7 +245,7 @@ def is_supporting_vote(store: Store, node: ChildNode, message: LatestMessage) -> ``` ### New `compute_proposer_boost` -This is a helper to compute the proposer boost. It applies the proposer boost to any ancestor of the proposer boost root taking into account the payload presence. There is one exception: if the requested node has the same root and slot as the block with the proposer boost root, then the proposer boost is applied to both empty and full versions of the node. +This is a helper to compute the proposer boost. It applies the proposer boost to any ancestor of the proposer boost root taking into account the payload presence. There is one exception: if the requested node has the same root and slot as the block with the proposer boost root, then the proposer boost is applied to both empty and full versions of the node. ```python def compute_proposer_boost(store: Store, state: BeaconState, node: ChildNode) -> Gwei: if store.proposer_boost_root == Root(): @@ -283,7 +283,7 @@ def compute_withhold_boost(store: Store, state: BeaconState, node: ChildNode) -> ``` ### New `compute_reveal_boost` -This is a similar helper to the last two, the only difference is that the reveal boost is only applied to the full version of the node when querying for the same slot as the revealed payload. +This is a similar helper to the last two, the only difference is that the reveal boost is only applied to the full version of the node when querying for the same slot as the revealed payload. ```python def compute_reveal_boost(store: Store, state: BeaconState, node: ChildNode) -> Gwei: @@ -302,7 +302,7 @@ def compute_reveal_boost(store: Store, state: BeaconState, node: ChildNode) -> G ### Modified `get_weight` -**Note:** `get_weight` is modified to only count votes for descending chains that support the status of a triple `Root, Slot, bool`, where the `bool` indicates if the block was full or not. `Slot` is needed for a correct implementation of `(Block, Slot)` voting. +**Note:** `get_weight` is modified to only count votes for descending chains that support the status of a triple `Root, Slot, bool`, where the `bool` indicates if the block was full or not. `Slot` is needed for a correct implementation of `(Block, Slot)` voting. ```python def get_weight(store: Store, node: ChildNode) -> Gwei: @@ -326,7 +326,7 @@ def get_weight(store: Store, node: ChildNode) -> Gwei: return attestation_score + proposer_score + builder_reveal_score + builder_withhold_score ``` -### Modified `get_head` +### Modified `get_head` **Note:** `get_head` is a modified to use the new `get_weight` function. It returns the `ChildNode` object corresponidng to the head block. @@ -343,13 +343,13 @@ def get_head(store: Store) -> ChildNode: while True: children = [ ChildNode(root=root, slot=block.slot, is_payload_present=present) for (root, block) in blocks.items() - if block.parent_root == best_child.root and block.slot > best_child.slot and + if block.parent_root == best_child.root and block.slot > best_child.slot and (best_child.root == justified_root or is_parent_node_full(store, block) == best_child.is_payload_present) for present in (True, False) if root in store.execution_payload_states or not present ] if len(children) == 0: return best_child - # if we have children we consider the current head advanced as a possible head + # if we have children we consider the current head advanced as a possible head highest_child_slot = max(child.slot for child in children) children += [ ChildNode(root=best_child.root, slot=best_child.slot + 1, is_payload_present=best_child.is_payload_present) @@ -360,10 +360,10 @@ def get_head(store: Store) -> ChildNode: # Ties are then broken by favoring full blocks # Ties then broken by favoring block with lexicographically higher root new_best_child = max(children, key=lambda child: ( - get_weight(store, child), + get_weight(store, child), blocks[child.root].slot, - is_payload_present(store, child.root), - child.is_payload_present, + is_payload_present(store, child.root), + child.is_payload_present, child.root ) ) @@ -376,7 +376,7 @@ def get_head(store: Store) -> ChildNode: ### Modified `on_block` -*Note*: The handler `on_block` is modified to consider the pre `state` of the given consensus beacon block depending not only on the parent block root, but also on the parent blockhash. In addition we delay the checking of blob data availability until the processing of the execution payload. +*Note*: The handler `on_block` is modified to consider the pre `state` of the given consensus beacon block depending not only on the parent block root, but also on the parent blockhash. In addition we delay the checking of blob data availability until the processing of the execution payload. ```python def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: @@ -449,14 +449,14 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: ### New `on_execution_payload` -The handler `on_execution_payload` is called when the node receives a `SignedExecutionPayloadEnvelope` to sync. +The handler `on_execution_payload` is called when the node receives a `SignedExecutionPayloadEnvelope` to sync. ```python def on_execution_payload(store: Store, signed_envelope: SignedExecutionPayloadEnvelope) -> None: """ Run ``on_execution_payload`` upon receiving a new execution payload. """ - envelope = signed_envelope.message + envelope = signed_envelope.message # The corresponding beacon block root needs to be known assert envelope.beacon_block_root in store.block_states @@ -472,7 +472,7 @@ def on_execution_payload(store: Store, signed_envelope: SignedExecutionPayloadEn # Add new state for this payload to the store store.execution_payload_states[envelope.beacon_block_root] = state -``` +``` ### `seconds_into_slot` @@ -497,7 +497,7 @@ def on_tick_per_slot(store: Store, time: uint64) -> None: # If this is a new slot, reset store.proposer_boost_root if current_slot > previous_slot: store.proposer_boost_root = Root() - else: + else: # Reset the payload boost if this is the attestation time if seconds_into_slot(store) >= SECONDS_PER_SLOT // INTERVALS_PER_SLOT: store.payload_withhold_boost_root = Root() @@ -534,7 +534,7 @@ def on_payload_attestation_message( assert data.slot == get_current_slot(store) # Verify the signature assert is_valid_indexed_payload_attestation( - state, + state, IndexedPayloadAttestation( attesting_indices=[ptc_message.validator_index], data=data, @@ -545,7 +545,7 @@ def on_payload_attestation_message( ptc_index = ptc.index(ptc_message.validator_index) ptc_vote = store.ptc_vote[data.beacon_block_root] ptc_vote[ptc_index] = data.payload_status - + # Only update payload boosts with attestations from a block if the block is for the current slot and it's early if is_from_block and data.slot + 1 != get_current_slot(store): return diff --git a/specs/_features/eip7732/fork.md b/specs/_features/eip7732/fork.md index 120e64fa46..fa03eb6886 100644 --- a/specs/_features/eip7732/fork.md +++ b/specs/_features/eip7732/fork.md @@ -61,7 +61,7 @@ def compute_fork_version(epoch: Epoch) -> Version: ### Fork trigger -TBD. This fork is defined for testing purposes, the EIP may be combined with other +TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. For now, we assume the condition will be triggered at epoch `EIP7732_FORK_EPOCH`. diff --git a/specs/_features/eip7732/p2p-interface.md b/specs/_features/eip7732/p2p-interface.md index d33dfaba31..a1dd1a2599 100644 --- a/specs/_features/eip7732/p2p-interface.md +++ b/specs/_features/eip7732/p2p-interface.md @@ -67,7 +67,7 @@ class BlobSidecar(Container): ##### Modified `verify_blob_sidecar_inclusion_proof` -`verify_blob_sidecar_inclusion_proof` is modified in EIP-7732 to account for the fact that the KZG commitments are included in the `ExecutionPayloadEnvelope` and no longer in the beacon block body. +`verify_blob_sidecar_inclusion_proof` is modified in EIP-7732 to account for the fact that the KZG commitments are included in the `ExecutionPayloadEnvelope` and no longer in the beacon block body. ```python def verify_blob_sidecar_inclusion_proof(blob_sidecar: BlobSidecar) -> bool: @@ -121,7 +121,7 @@ EIP-7732 introduces new global topics for execution header, execution payload an [Modified in EIP-7732] -The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in [the Beacon Chain changes](./beacon-chain.md). +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in [the Beacon Chain changes](./beacon-chain.md). There are no new validations for this topic. However, all validations with regards to the `ExecutionPayload` are removed: @@ -137,7 +137,7 @@ There are no new validations for this topic. However, all validations with regar And instead the following validations are set in place with the alias `header = signed_execution_payload_header.message`: - If `execution_payload` verification of block's execution payload parent by an execution node **is complete**: - - [REJECT] The block's execution payload parent (defined by `header.parent_block_hash`) passes all validation. + - [REJECT] The block's execution payload parent (defined by `header.parent_block_hash`) passes all validation. - [REJECT] The block's parent (defined by `block.parent_root`) passes validation. ###### `execution_payload` @@ -148,12 +148,12 @@ The following validations MUST pass before forwarding the `signed_execution_payl - _[IGNORE]_ The envelope's block root `envelope.block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue payload for processing once the block is retrieved). - _[IGNORE]_ The node has not seen another valid `SignedExecutionPayloadEnvelope` for this block root from this builder. - -Let `block` be the block with `envelope.beacon_block_root`. + +Let `block` be the block with `envelope.beacon_block_root`. Let `header` alias `block.body.signed_execution_payload_header.message` (notice that this can be obtained from the `state.signed_execution_payload_header`) -- _[REJECT]_ `block` passes validation. -- _[REJECT]_ `envelope.builder_index == header.builder_index` -- if `envelope.payload_withheld == False` then +- _[REJECT]_ `block` passes validation. +- _[REJECT]_ `envelope.builder_index == header.builder_index` +- if `envelope.payload_withheld == False` then - _[REJECT]_ `payload.block_hash == header.block_hash` - _[REJECT]_ The builder signature, `signed_execution_payload_envelope.signature`, is valid with respect to the builder's public key. @@ -163,14 +163,14 @@ This topic is used to propagate signed payload attestation message. The following validations MUST pass before forwarding the `payload_attestation_message` on the network, assuming the alias `data = payload_attestation_message.data`: -- _[IGNORE]_ The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`. -- _[REJECT]_ The message's payload status is a valid status, i.e. `data.payload_status < PAYLOAD_INVALID_STATUS`. -- _[IGNORE]_ The `payload_attestation_message` is the first valid message received from the validator with index `payload_attestation_message.validate_index`. -- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). -- _[REJECT]_ The message's block `data.beacon_block_root` passes validation. -- _[REJECT]_ The message's validator index is within the payload committee in `get_ptc(state, data.slot)`. The `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice. -- _[REJECT]_ The message's signature of `payload_attestation_message.signature` is valid with respect to the validator index. - +- _[IGNORE]_ The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`. +- _[REJECT]_ The message's payload status is a valid status, i.e. `data.payload_status < PAYLOAD_INVALID_STATUS`. +- _[IGNORE]_ The `payload_attestation_message` is the first valid message received from the validator with index `payload_attestation_message.validate_index`. +- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). +- _[REJECT]_ The message's block `data.beacon_block_root` passes validation. +- _[REJECT]_ The message's validator index is within the payload committee in `get_ptc(state, data.slot)`. The `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice. +- _[REJECT]_ The message's signature of `payload_attestation_message.signature` is valid with respect to the validator index. + ###### `execution_payload_header` This topic is used to propagate signed bids as `SignedExecutionPayloadHeader`. @@ -182,8 +182,8 @@ The following validations MUST pass before forwarding the `signed_execution_payl - _[REJECT]_ The signed builder bid, `header.builder_index` is a valid, active, and non-slashed builder index in state. - _[IGNORE]_ The signed builder bid value, `header.value`, is less or equal than the builder's balance in state. i.e. `MIN_BUILDER_BALANCE + header.value < state.builder_balances[header.builder_index]`. - _[IGNORE]_ `header.parent_block_hash` is the block hash of a known execution payload in fork choice. -_ _[IGNORE]_ `header.parent_block_root` is the hash tree root of a known beacon block in fork choice. -- _[IGNORE]_ `header.slot` is the current slot or the next slot. +_ _[IGNORE]_ `header.parent_block_root` is the hash tree root of a known beacon block in fork choice. +- _[IGNORE]_ `header.slot` is the current slot or the next slot. - _[REJECT]_ The builder signature, `signed_execution_payload_header_envelope.signature`, is valid with respect to the `header_envelope.builder_index`. ### The Req/Resp domain @@ -220,7 +220,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | | `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | -| `EIP7732_FORK_VERSION` | `eip7732.SignedBeaconBlock` | +| `EIP7732_FORK_VERSION` | `eip7732.SignedBeaconBlock` | ##### BlobSidecarsByRoot v2 diff --git a/specs/_features/eip7732/validator.md b/specs/_features/eip7732/validator.md index 6a6cbeecef..3a4d4e93ea 100644 --- a/specs/_features/eip7732/validator.md +++ b/specs/_features/eip7732/validator.md @@ -1,10 +1,10 @@ # EIP-7732 -- Honest Validator -This document represents the changes and additions to the Honest validator guide included in the EIP-7732 fork. +This document represents the changes and additions to the Honest validator guide included in the EIP-7732 fork. -**Table of Contents** +**Table of Contents** - [Validator assignment](#validator-assignment) - [Lookahead](#lookahead) @@ -33,7 +33,7 @@ def get_ptc_assignment( validator_index: ValidatorIndex) -> Optional[Slot]: """ Returns the slot during the requested epoch in which the validator with index `validator_index` - is a member of the PTC. Returns None if no assignment is found. + is a member of the PTC. Returns None if no assignment is found. """ next_epoch = Epoch(get_current_epoch(state) + 1) assert epoch <= next_epoch @@ -49,22 +49,22 @@ def get_ptc_assignment( [New in EIP-7732] -`get_ptc_assignment` should be called at the start of each epoch to get the assignment for the next epoch (`current_epoch + 1`). A validator should plan for future assignments by noting their assigned PTC slot. +`get_ptc_assignment` should be called at the start of each epoch to get the assignment for the next epoch (`current_epoch + 1`). A validator should plan for future assignments by noting their assigned PTC slot. ## Beacon chain responsibilities All validator responsibilities remain unchanged other than the following: -- Proposers are no longer required to broadcast `BlobSidecar` objects, as this becomes a builder's duty. -- Some validators are selected per slot to become PTC members, these validators must broadcast `PayloadAttestationMessage` objects during the assigned slot before the deadline of `3 * SECONDS_PER_SLOT // INTERVALS_PER_SLOT` seconds into the slot. +- Proposers are no longer required to broadcast `BlobSidecar` objects, as this becomes a builder's duty. +- Some validators are selected per slot to become PTC members, these validators must broadcast `PayloadAttestationMessage` objects during the assigned slot before the deadline of `3 * SECONDS_PER_SLOT // INTERVALS_PER_SLOT` seconds into the slot. ### Attestation -Attestation duties are not changed for validators, however the attestation deadline is implicitly changed by the change in `INTERVALS_PER_SLOT`. +Attestation duties are not changed for validators, however the attestation deadline is implicitly changed by the change in `INTERVALS_PER_SLOT`. ### Sync Committee participations -Sync committee duties are not changed for validators, however the submission deadline is implicitly changed by the change in `INTERVALS_PER_SLOT`. +Sync committee duties are not changed for validators, however the submission deadline is implicitly changed by the change in `INTERVALS_PER_SLOT`. ### Block proposal @@ -74,32 +74,32 @@ Validators are still expected to propose `SignedBeaconBlock` at the beginning of #### Constructing the new `signed_execution_payload_header` field in `BeaconBlockBody` To obtain `signed_execution_payload_header`, a block proposer building a block on top of a `state` must take the following actions: -* Listen to the `execution_payload_header` gossip global topic and save an accepted `signed_execution_payload_header` from a builder. Proposer MAY obtain these signed messages by other off-protocol means. -* The `signed_execution_payload_header` must satisfy the verification conditions found in `process_execution_payload_header`, that is +* Listen to the `execution_payload_header` gossip global topic and save an accepted `signed_execution_payload_header` from a builder. Proposer MAY obtain these signed messages by other off-protocol means. +* The `signed_execution_payload_header` must satisfy the verification conditions found in `process_execution_payload_header`, that is - The header signature must be valid - The builder balance can cover the header value - The header slot is for the proposal block slot - - The header parent block hash equals the state's `latest_block_hash`. + - The header parent block hash equals the state's `latest_block_hash`. - The header parent block root equals the current block's `parent_root`. * Select one bid and set `body.signed_execution_payload_header = signed_execution_payload_header` #### Constructing the new `payload_attestations` field in `BeaconBlockBody` -Up to `MAX_PAYLOAD_ATTESTATIONS`, aggregate payload attestations can be included in the block. The validator will have to -* Listen to the `payload_attestation_message` gossip global topic +Up to `MAX_PAYLOAD_ATTESTATIONS`, aggregate payload attestations can be included in the block. The validator will have to +* Listen to the `payload_attestation_message` gossip global topic * The payload attestations added must satisfy the verification conditions found in payload attestation gossip validation and payload attestation processing. This means - The `data.beacon_block_root` corresponds to `block.parent_root`. - - The slot of the parent block is exactly one slot before the proposing slot. - - The signature of the payload attestation data message verifies correctly. -* The proposer needs to aggregate all payload attestations with the same data into a given `PayloadAttestation` object. For this it needs to fill the `aggregation_bits` field by using the relative position of the validator indices with respect to the PTC that is obtained from `get_ptc(state, block_slot - 1)`. -* The proposer should only include payload attestations that are consistent with the current block they are proposing. That is, if the previous block had a payload, they should only include attestations with `payload_status = PAYLOAD_PRESENT`. Proposers are penalized for attestations that are not-consistent with their view. + - The slot of the parent block is exactly one slot before the proposing slot. + - The signature of the payload attestation data message verifies correctly. +* The proposer needs to aggregate all payload attestations with the same data into a given `PayloadAttestation` object. For this it needs to fill the `aggregation_bits` field by using the relative position of the validator indices with respect to the PTC that is obtained from `get_ptc(state, block_slot - 1)`. +* The proposer should only include payload attestations that are consistent with the current block they are proposing. That is, if the previous block had a payload, they should only include attestations with `payload_status = PAYLOAD_PRESENT`. Proposers are penalized for attestations that are not-consistent with their view. #### Blob sidecars The blob sidecars are no longer broadcast by the validator, and thus their construction is not necessary. This deprecates the corresponding sections from the honest validator guide in the Electra fork, moving them, albeit with some modifications, to the [honest Builder guide](./builder.md) ### Payload timeliness attestation -Some validators are selected to submit payload timeliness attestations. Validators should call `get_ptc_assignment` at the beginning of an epoch to be prepared to submit their PTC attestations during the next epoch. +Some validators are selected to submit payload timeliness attestations. Validators should call `get_ptc_assignment` at the beginning of an epoch to be prepared to submit their PTC attestations during the next epoch. A validator should create and broadcast the `payload_attestation_message` to the global execution attestation subnet not after `SECONDS_PER_SLOT * 3 / INTERVALS_PER_SLOT` seconds since the start of `slot` @@ -109,9 +109,9 @@ If a validator is in the payload attestation committee for the current slot (as according to the logic in `get_payload_attestation_message` below and broadcast it not after `SECONDS_PER_SLOT * 3 / INTERVALS_PER_SLOT` seconds since the start of the slot, to the global `payload_attestation_message` pubsub topic. The validator creates `payload_attestation_message` as follows: -* If the validator has not seen any beacon block for the assigned slot, do not submit a payload attestation. It will be ignored anyway. +* If the validator has not seen any beacon block for the assigned slot, do not submit a payload attestation. It will be ignored anyway. * Set `data.beacon_block_root` be the HTR of the beacon block seen for the assigned slot -* Set `data.slot` to be the assigned slot. +* Set `data.slot` to be the assigned slot. * Set `data.payload_status` as follows - If a `SignedExecutionPayloadEnvelope` has been seen referencing the block `data.beacon_block_root` and the envelope has `payload_withheld = False`, set to `PAYLOAD_PRESENT`. - If a `SignedExecutionPayloadEnvelope` has been seen referencing the block `data.beacon_block_root` and the envelope has `payload_withheld = True`, set to `PAYLOAD_WITHHELD`. @@ -119,7 +119,7 @@ The validator creates `payload_attestation_message` as follows: * Set `payload_attestation_message.validator_index = validator_index` where `validator_index` is the validator chosen to submit. The private key mapping to `state.validators[validator_index].pubkey` is used to sign the payload timeliness attestation. * Sign the `payload_attestation_message.data` using the helper `get_payload_attestation_message_signature`. -Notice that the attester only signs the `PayloadAttestationData` and not the `validator_index` field in the message. Proposers need to aggregate these attestations as described above. +Notice that the attester only signs the `PayloadAttestationData` and not the `validator_index` field in the message. Proposers need to aggregate these attestations as described above. ```python def get_payload_attestation_message_signature( @@ -129,6 +129,6 @@ def get_payload_attestation_message_signature( return bls.Sign(privkey, signing_root) ``` -**Remark** Validators do not need to check the full validity of the `ExecutionPayload` contained in within the envelope, but the checks in the [P2P guide](./p2p-interface.md) should pass for the `SignedExecutionPayloadEnvelope`. +**Remark** Validators do not need to check the full validity of the `ExecutionPayload` contained in within the envelope, but the checks in the [P2P guide](./p2p-interface.md) should pass for the `SignedExecutionPayloadEnvelope`. diff --git a/specs/_features/sharding/beacon-chain.md b/specs/_features/sharding/beacon-chain.md index e67bc09ed6..35b6776028 100644 --- a/specs/_features/sharding/beacon-chain.md +++ b/specs/_features/sharding/beacon-chain.md @@ -82,7 +82,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | - | | `MAX_SHARDS` | `uint64(2**12)` (= 4,096) | Theoretical max shard count (used to determine data structure sizes) | | `ACTIVE_SHARDS` | `uint64(2**8)` (= 256) | Initial shard count | -| `MAX_PROPOSER_BLOCKS_BETWEEN_BUILDER_BLOCKS` | `uint64(2**4)` (= 16) | TODO: Need to define what happens if there were more blocks without builder blocks | +| `MAX_PROPOSER_BLOCKS_BETWEEN_BUILDER_BLOCKS` | `uint64(2**4)` (= 16) | TODO: Need to define what happens if there were more blocks without builder blocks | ### Time parameters @@ -100,7 +100,7 @@ With the introduction of builder blocks the number of slots per epoch is doubled ## Configuration -Note: Some preset variables may become run-time configurable for testnets, but default to a preset while the spec is unstable. +Note: Some preset variables may become run-time configurable for testnets, but default to a preset while the spec is unstable. E.g. `ACTIVE_SHARDS` and `SAMPLES_PER_BLOB`. ### Time parameters @@ -129,12 +129,12 @@ class BuilderBlockBid(Container): bid: Gwei # Block builder bid paid to proposer validator_index: ValidatorIndex # Validator index for this bid - + # Block builders use an Eth1 address -- need signature as # block bid and data gas base fees will be charged to this address signature_y_parity: bool signature_r: uint256 - signature_s: uint256 + signature_s: uint256 ``` #### `BuilderBlockBidWithRecipientAddress` @@ -156,7 +156,7 @@ class ShardedCommitmentsContainer(Container): # The sizes of the blocks encoded in the commitments (last builder and all beacon blocks since) included_block_sizes: List[uint64, MAX_PROPOSER_BLOCKS_BETWEEN_BUILDER_BLOCKS + 1] - + # Number of commitments that are for sharded data (no blocks) included_sharded_data_commitments: uint64 @@ -192,7 +192,7 @@ class BeaconState(bellatrix.BeaconState): class BuilderBlockData(Container): execution_payload: ExecutionPayload sharded_commitments_container: ShardedCommitmentsContainer -``` +``` #### `BeaconBlockBody` diff --git a/specs/_features/sharding/polynomial-commitments.md b/specs/_features/sharding/polynomial-commitments.md index f52d950664..865328597e 100644 --- a/specs/_features/sharding/polynomial-commitments.md +++ b/specs/_features/sharding/polynomial-commitments.md @@ -203,7 +203,7 @@ def low_degree_check(commitments: List[KZGCommitment]): coefs.append( - (r_to_K - 1) * bls_modular_inverse(K * roots[i * (K - 1) % K] * (r - roots[i])) % BLS_MODULUS) for i in range(d + 1): coefs[i] = (coefs[i] + B(r) * bls_modular_inverse(Bprime(r) * (r - roots[i]))) % BLS_MODULUS - + assert elliptic_curve_lincomb(commitments, coefs) == bls.inf_G1() ``` @@ -279,7 +279,7 @@ def interpolate_polynomial(xs: List[BLSFieldElement], ys: List[BLSFieldElement]) summand, [weight_adjustment, ((BLS_MODULUS - weight_adjustment) * xs[i])] ) r = add_polynomials(r, summand) - + return r ``` @@ -300,7 +300,7 @@ def evaluate_polynomial_in_evaluation_form(poly: BLSPolynomialByEvaluations, x: return r def Aprime(z): - return field_elements_per_blob * pow(z, field_elements_per_blob - 1, BLS_MODULUS) + return field_elements_per_blob * pow(z, field_elements_per_blob - 1, BLS_MODULUS) r = 0 inverses = [bls_modular_inverse(z - x) for z in roots] @@ -312,7 +312,7 @@ def evaluate_polynomial_in_evaluation_form(poly: BLSPolynomialByEvaluations, x: ## KZG Operations -We are using the KZG10 polynomial commitment scheme (Kate, Zaverucha and Goldberg, 2010: https://www.iacr.org/archive/asiacrypt2010/6477178/6477178.pdf). +We are using the KZG10 polynomial commitment scheme (Kate, Zaverucha and Goldberg, 2010: https://www.iacr.org/archive/asiacrypt2010/6477178/6477178.pdf). ### Elliptic curve helper functions @@ -387,7 +387,7 @@ def verify_kzg_multiproof(commitment: KZGCommitment, ```python def verify_degree_proof(commitment: KZGCommitment, degree_bound: uint64, proof: KZGCommitment): """ - Verifies that the commitment is of polynomial degree < degree_bound. + Verifies that the commitment is of polynomial degree < degree_bound. """ assert ( diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 9c2cb389a3..2d40535586 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -96,7 +96,7 @@ def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: | --------------------- | ------------------------------------------------------------------------------- | | `BLS_G1_GENERATOR` | `BLSG1Point('0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb') # noqa: E501` | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | -| `CURDLEPROOFS_CRS` | TBD | +| `CURDLEPROOFS_CRS` | TBD | ### Curdleproofs and opening proofs @@ -423,7 +423,7 @@ def add_validator_to_registry(state: BeaconState, # [New in Whisk] k = get_unique_whisk_k(state, ValidatorIndex(len(state.validators) - 1)) state.whisk_trackers.append(get_initial_tracker(k)) - state.whisk_k_commitments.append(get_k_commitment(k)) + state.whisk_k_commitments.append(get_k_commitment(k)) ``` ### `get_beacon_proposer_index` diff --git a/specs/bellatrix/p2p-interface.md b/specs/bellatrix/p2p-interface.md index 617f6f1fc7..eb10eb7e1c 100644 --- a/specs/bellatrix/p2p-interface.md +++ b/specs/bellatrix/p2p-interface.md @@ -146,7 +146,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: With the addition of `ExecutionPayload` to `BeaconBlock`s, there is a dynamic field -- `transactions` -- which can validly exceed the `GOSSIP_MAX_SIZE` limit (1 MiB) put in -place at Phase 0, so GOSSIP_MAX_SIZE has increased to 10 Mib on the network. +place at Phase 0, so GOSSIP_MAX_SIZE has increased to 10 Mib on the network. At the `GAS_LIMIT` (~30M) currently seen on mainnet in 2021, a single transaction filled entirely with data at a cost of 16 gas per byte can create a valid `ExecutionPayload` of ~2 MiB. Thus we need a size limit to at least account for diff --git a/specs/capella/validator.md b/specs/capella/validator.md index 6f30ea6e4d..624a895b9b 100644 --- a/specs/capella/validator.md +++ b/specs/capella/validator.md @@ -110,7 +110,7 @@ Validator balances are withdrawn periodically via an automatic process. For exit There is one prerequisite for this automated process: the validator's withdrawal credentials pointing to an execution layer address, i.e. having an `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. -If a validator has a `BLS_WITHDRAWAL_PREFIX` withdrawal credential prefix, to participate in withdrawals the validator must +If a validator has a `BLS_WITHDRAWAL_PREFIX` withdrawal credential prefix, to participate in withdrawals the validator must create a one-time message to change their withdrawal credential from the version authenticated with a BLS key to the version compatible with the execution layer. This message -- a `BLSToExecutionChange` -- is available starting in Capella diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 84678f8a61..f73b17309b 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -438,7 +438,7 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], for commitment, y in zip(commitments, ys)] C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys] C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers) - + return bls.pairing_check([ [bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[1]))], [bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2()] diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 7c6d9fe1fa..f86ffc7ee8 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -994,7 +994,7 @@ def notify_new_payload(self: ExecutionEngine, parent_beacon_block_root: Root, execution_requests_list: list[bytes]) -> bool: """ - Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` + Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` are valid with respect to ``self.execution_state``. """ ... diff --git a/specs/phase0/weak-subjectivity.md b/specs/phase0/weak-subjectivity.md index 52953c34df..00ab559b32 100644 --- a/specs/phase0/weak-subjectivity.md +++ b/specs/phase0/weak-subjectivity.md @@ -86,9 +86,9 @@ A detailed analysis of the calculation of the weak subjectivity period is made i ```python def compute_weak_subjectivity_period(state: BeaconState) -> uint64: """ - Returns the weak subjectivity period for the current ``state``. + Returns the weak subjectivity period for the current ``state``. This computation takes into account the effect of: - - validator set churn (bounded by ``get_validator_churn_limit()`` per epoch), and + - validator set churn (bounded by ``get_validator_churn_limit()`` per epoch), and - validator balance top-ups (bounded by ``MAX_DEPOSITS * SLOTS_PER_EPOCH`` per epoch). A detailed calculation can be found at: https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf @@ -113,7 +113,7 @@ def compute_weak_subjectivity_period(state: BeaconState) -> uint64: ws_period += ( 3 * N * D * t // (200 * Delta * (T - t)) ) - + return ws_period ``` diff --git a/ssz/merkle-proofs.md b/ssz/merkle-proofs.md index ffc543f95e..36d0b83ac1 100644 --- a/ssz/merkle-proofs.md +++ b/ssz/merkle-proofs.md @@ -71,7 +71,7 @@ Note that the generalized index has the convenient property that the two childre ```python def merkle_tree(leaves: Sequence[Bytes32]) -> Sequence[Bytes32]: """ - Return an array representing the tree nodes by generalized index: + Return an array representing the tree nodes by generalized index: [0, 1, 2, 3, 4, 5, 6, 7], where each layer is a power of 2. The 0 index is ignored. The 1 index is the root. The result will be twice the size as the padded bottom layer for the input leaves. """ diff --git a/sync/optimistic.md b/sync/optimistic.md index 1fd1ba46e6..fd83f9a691 100644 --- a/sync/optimistic.md +++ b/sync/optimistic.md @@ -326,7 +326,7 @@ optimistic blocks (and vice-versa). ### Why sync optimistically? -Most execution engines use state sync as a default sync mechanism on Ethereum Mainnet +Most execution engines use state sync as a default sync mechanism on Ethereum Mainnet because executing blocks from genesis takes several weeks on commodity hardware. State sync requires the knowledge of the current head of the chain to converge eventually. diff --git a/tests/README.md b/tests/README.md index 8c281155c5..1ffa17239a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -15,7 +15,7 @@ Use an OS that has Python 3.8 or above. For example, Debian 11 (bullseye) git clone https://github.com/ethereum/consensus-specs.git cd consensus-specs ``` -3. Create the specifications and tests: +3. Create the specifications and tests: ```sh make install_test make pyspec @@ -32,7 +32,7 @@ To read more about creating the environment, [see here](core/pyspec/README.md). . venv/bin/activate ``` 2. Run a sanity check test against Altair fork: - ```sh + ```sh cd tests/core/pyspec python -m pytest -k test_empty_block_transition --fork altair eth2spec ``` @@ -49,21 +49,21 @@ To read more about creating the environment, [see here](core/pyspec/README.md). =============================== warnings summary =============================== ../../../venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2 - /home/qbzzt1/consensus-specs/venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2: - DeprecationWarning: The toolz.compatibility module is no longer needed in Python 3 and has - been deprecated. Please import these utilities directly from the standard library. This + /home/qbzzt1/consensus-specs/venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2: + DeprecationWarning: The toolz.compatibility module is no longer needed in Python 3 and has + been deprecated. Please import these utilities directly from the standard library. This module will be removed in a future release. warnings.warn("The toolz.compatibility module is no longer " -- Docs: https://docs.pytest.org/en/stable/warnings.html - ================ 3 passed, 626 deselected, 1 warning in 16.81s ================= + ================ 3 passed, 626 deselected, 1 warning in 16.81s ================= ``` ## The "Hello, World" of Consensus Spec Tests One of the `test_empty_block_transition` tests is implemented by a function with the same -name located in +name located in [`~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py). To learn how consensus spec tests are written, let's go over the code: @@ -94,10 +94,10 @@ This type of test receives two parameters: ```python pre_slot = state.slot -``` +``` A slot is a unit of time (every 12 seconds in mainnet), for which a specific validator (selected randomly but in a -deterministic manner) is a proposer. The proposer can propose a block during that slot. +deterministic manner) is a proposer. The proposer can propose a block during that slot. ```python pre_eth1_votes = len(state.eth1_data_votes) @@ -151,7 +151,7 @@ More `yield` statements. The output of a consensus test is: # Check that the new parent root is correct assert spec.get_block_root_at_slot(state, pre_slot) == signed_block.message.parent_root - + # Random data changed assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != pre_mix ``` @@ -160,16 +160,16 @@ Finally we assertions that test the transition was legitimate. In this case we h 1. One item was added to `eth1_data_votes` 2. The new block's `parent_root` is the same as the block in the previous location -3. The random data that every block includes was changed. +3. The random data that every block includes was changed. ## New Tests The easiest way to write a new test is to copy and modify an existing one. For example, -lets write a test where the first slot of the beacon chain is empty (because the assigned +lets write a test where the first slot of the beacon chain is empty (because the assigned proposer is offline, for example), and then there's an empty block in the second slot. -We already know how to accomplish most of what we need for this test, but the only way we know +We already know how to accomplish most of what we need for this test, but the only way we know to advance the state is `state_transition_and_sign_block`, a function that also puts a block into the slot. So let's see if the function's definition tells us how to advance the state without a block. @@ -180,7 +180,7 @@ First, we need to find out where the function is located. Run: find . -name '*.py' -exec grep 'def state_transition_and_sign_block' {} \; -print ``` -And you'll find that the function is defined in +And you'll find that the function is defined in [`eth2spec/test/helpers/state.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/state.py). Looking in that file, we see that the second function is: @@ -209,7 +209,7 @@ This looks like exactly what we need. So we add this call before we create the e . ``` -That's it. Our new test works (copy `test_empty_block_transition`, rename it, add the `next_slot` call, and then run it to +That's it. Our new test works (copy `test_empty_block_transition`, rename it, add the `next_slot` call, and then run it to verify this). @@ -218,7 +218,7 @@ verify this). It is important to make sure that the system rejects invalid input, so our next step is to deal with cases where the protocol is supposed to reject something. To see such a test, look at `test_prev_slot_block_transition` (in the same -file we used previously, +file we used previously, [`~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py)). ```python @@ -249,7 +249,7 @@ Transition to the new slot, which naturally has a different proposer. ``` Specify that the function `transition_unsigned_block` will cause an assertion error. -You can see this function in +You can see this function in [`~/consensus-specs/tests/core/pyspec/eth2spec/test/helpers/block.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/block.py), and one of the tests is that the block must be for this slot: > ```python @@ -265,14 +265,14 @@ be called later. ``` Set the block's state root to the current state hash tree root, which identifies this block as -belonging to this slot (even though it was created for the previous slot). +belonging to this slot (even though it was created for the previous slot). -```python +```python signed_block = sign_block(spec, state, block, proposer_index=proposer_index) ``` Notice that `proposer_index` is the variable we set earlier, *before* we advanced -the slot with `spec.process_slots(state, state.slot + 1)`. It is not the proposer +the slot with `spec.process_slots(state, state.slot + 1)`. It is not the proposer for the current state. ```python @@ -296,8 +296,8 @@ includes the block hash of the proposed new head of the execution layer. For every slot there is also a randomly selected committee of validators that needs to vote whether the new consensus layer block is valid, which requires the proposed head of the execution chain to -also be a valid block. These votes are called [attestations](https://notes.ethereum.org/@hww/aggregation#112-Attestation), -and they are sent as independent messages. The proposer for a block is able to include attestations from previous slots, +also be a valid block. These votes are called [attestations](https://notes.ethereum.org/@hww/aggregation#112-Attestation), +and they are sent as independent messages. The proposer for a block is able to include attestations from previous slots, which is how they get on chain to form consensus, reward honest validators, etc. [You can see a simple successful attestation test here](https://github.com/ethereum/consensus-specs/blob/926e5a3d722df973b9a12f12c015783de35cafa9/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py#L26-L30): @@ -326,8 +326,8 @@ To see an attestion "from the inside" we need to follow it. > ``` > > Only two parameters, `spec` and `state` are required. However, there are four other parameters that can affect -> the attestation created by this function. -> +> the attestation created by this function. +> > > ```python > # If filter_participant_set filters everything, the attestation has 0 participants, and cannot be signed. @@ -345,10 +345,10 @@ To see an attestion "from the inside" we need to follow it. > attestation_data = build_attestation_data( > spec, state, slot=slot, index=index > ) -> ``` +> ``` > -> Build the actual attestation. You can see this function -> [here](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L53-L85) +> Build the actual attestation. You can see this function +> [here](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L53-L85) > to see the exact data in an attestation. > > ```python @@ -358,17 +358,17 @@ To see an attestion "from the inside" we need to follow it. > attestation_data.index, > ) > ``` -> +> > This is the committee that is supposed to approve or reject the proposed block. -> -> ```python -> +> +> ```python +> > committee_size = len(beacon_committee) > aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) > ``` -> +> > There's a bit for every committee member to see if it approves or not. -> +> > ```python > attestation = spec.Attestation( > aggregation_bits=aggregation_bits, @@ -376,15 +376,15 @@ To see an attestion "from the inside" we need to follow it. > ) > # fill the attestation with (optionally filtered) participants, and optionally sign it > fill_aggregate_attestation(spec, state, attestation, signed=signed, filter_participant_set=filter_participant_set) -> -> return attestation +> +> return attestation > ``` ```python next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY) ``` -Attestations have to appear after the block they attest for, so we advance +Attestations have to appear after the block they attest for, so we advance `spec.MIN_ATTESTATION_INCLUSION_DELAY` slots before creating the block that includes the attestation. Currently a single block is sufficient, but that may change in the future. @@ -392,7 +392,7 @@ Currently a single block is sufficient, but that may change in the future. yield from run_attestation_processing(spec, state, attestation) ``` -[This function](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L13-L50) +[This function](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L13-L50) processes the attestation and returns the result. @@ -419,15 +419,15 @@ In the last line you can see two conditions being asserted: arrive too early. 2. `state.slot <= data.slot + SLOTS_PER_EPOCH` which verifies that the attestation doesn't arrive too late. - + This is how the consensus layer tests deal with edge cases, by asserting the conditions required for the -values to be legitimate. In the case of these particular conditions, they are tested +values to be legitimate. In the case of these particular conditions, they are tested [here](https://github.com/ethereum/consensus-specs/blob/926e5a3d722df973b9a12f12c015783de35cafa9/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py#L87-L104). One test checks what happens if the attestation is too early, and another if it is too late. However, it is not enough to ensure we reject invalid blocks. It is also necessary to ensure we accept all valid blocks. You saw earlier -a test (`test_success`) that tested that being `MIN_ATTESTATION_INCLUSION_DELAY` after the data for which we attest is enough. -Now we'll write a similar test that verifies that being `SLOTS_PER_EPOCH` away is still valid. To do this, we modify the +a test (`test_success`) that tested that being `MIN_ATTESTATION_INCLUSION_DELAY` after the data for which we attest is enough. +Now we'll write a similar test that verifies that being `SLOTS_PER_EPOCH` away is still valid. To do this, we modify the `test_after_epoch_slots` function. We need two changes: 1. Call `transition_to_slot_via_block` with one less slot to advance @@ -445,7 +445,7 @@ def test_almost_after_epoch_slots(spec, state): transition_to_slot_via_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH) yield from run_attestation_processing(spec, state, attestation) -``` +``` Add this function to the file `consensus-specs/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py`, and run the test against Altair fork: @@ -463,7 +463,7 @@ You should see it ran successfully (although you might get a warning, you can ig So far we've ran tests against the formal specifications. This is a way to check the specifications are what we expect, but it doesn't actually check the beacon chain clients. The way these tests get applied -by clients is that every few weeks +by clients is that every few weeks [new test specifications are released](https://github.com/ethereum/consensus-spec-tests/releases), in a format [documented here](https://github.com/ethereum/consensus-specs/tree/dev/tests/formats). All the consensus layer clients implement test-runners that consume the test vectors in this standard format. diff --git a/tests/core/pyspec/eth2spec/config/README.md b/tests/core/pyspec/eth2spec/config/README.md index c03d890c20..a61461f01a 100644 --- a/tests/core/pyspec/eth2spec/config/README.md +++ b/tests/core/pyspec/eth2spec/config/README.md @@ -19,5 +19,5 @@ spec.config = spec.Configuration(**config_util.load_config_file(Path('mytestnet. ``` Note: previously the testnet config files included both preset and runtime-configuration data. -The new config loader is compatible with this: all config vars are loaded from the file, -but those that have become presets can be ignored. +The new config loader is compatible with this: all config vars are loaded from the file, +but those that have become presets can be ignored. diff --git a/tests/core/pyspec/eth2spec/gen_helpers/README.md b/tests/core/pyspec/eth2spec/gen_helpers/README.md index bf791ccfea..8fda6b585e 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/README.md +++ b/tests/core/pyspec/eth2spec/gen_helpers/README.md @@ -17,10 +17,10 @@ Options: If true, all cases will run regardless, and files will be overwritten. Other existing files are not deleted. --c CONFIGS_PATH -- The directory to load configs for pyspec from. A config is a simple key-value yaml file. +-c CONFIGS_PATH -- The directory to load configs for pyspec from. A config is a simple key-value yaml file. Use `../../configs/` when running from the root dir of a generator, and requiring the standard spec configs. -[-l [CONFIG_LIST [CONFIG_LIST ...]]] -- Optional. Define which configs to run. +[-l [CONFIG_LIST [CONFIG_LIST ...]]] -- Optional. Define which configs to run. Test providers loading other configs will be ignored. If none are specified, no config will be ignored. ``` @@ -45,10 +45,10 @@ The yielding pattern is: Test part output kinds: - `ssz`: value is expected to be a `bytes`, and the raw data is written to a `.ssz_snappy` file. - `data`: value is expected to be any Python object that can be dumped as YAML. Output is written to `.yaml` -- `meta`: these key-value pairs are collected into a dict, and then collectively written to a metadata +- `meta`: these key-value pairs are collected into a dict, and then collectively written to a metadata file named `meta.yaml`, if anything is yielded with `meta` empty. The `vector_test()` decorator can detect pyspec SSZ types, and output them both as `data` and `ssz`, for the test consumer to choose. -Note that the yielded outputs are processed before the test continues. It is safe to yield information that later mutates, +Note that the yielded outputs are processed before the test continues. It is safe to yield information that later mutates, as the output will already be encoded to yaml or ssz bytes. This avoids the need to deep-copy the whole object. diff --git a/tests/formats/README.md b/tests/formats/README.md index ec495daa5b..4811595ba8 100644 --- a/tests/formats/README.md +++ b/tests/formats/README.md @@ -50,7 +50,7 @@ Test formats: ## Glossary - `generator`: a program that outputs one or more test-cases, each organized into a `config > runner > handler > suite` hierarchy. -- `config`: tests are grouped by configuration used for spec presets. In addition to the standard configurations, +- `config`: tests are grouped by configuration used for spec presets. In addition to the standard configurations, `general` may be used as a catch-all for tests not restricted to one configuration. (E.g. BLS). - `type`: the specialization of one single `generator`. E.g. epoch processing. - `runner`: where a generator is a *"producer"*, this is the *"consumer"*. @@ -59,10 +59,10 @@ Test formats: To facilitate this, you specify a `handler`: the runner can deal with the format by using the specified handler. - `suite`: a directory containing test cases that are coherent. Each `suite` under the same `handler` shares the same format. This is an organizational/cosmetic hierarchy layer. -- `case`: a test case, a directory in a `suite`. A case can be anything in general, +- `case`: a test case, a directory in a `suite`. A case can be anything in general, but its format should be well-defined in the documentation corresponding to the `type` (and `handler`). - `case part`: a test case consists of different files, possibly in different formats, to facilitate the specific test case format better. - Optionally, a `meta.yaml` is included to declare meta-data for the test, e.g. BLS requirements. + Optionally, a `meta.yaml` is included to declare meta-data for the test, e.g. BLS requirements. ## Test format philosophy @@ -70,12 +70,12 @@ Test formats: The configuration constant types are: - Never changing: genesis data. -- Changing, but reliant on old value: e.g. an epoch time may change, but if you want to do the conversion +- Changing, but reliant on old value: e.g. an epoch time may change, but if you want to do the conversion `(genesis data, timestamp) -> epoch number`, you end up needing both constants. - Changing, but kept around during fork transition: finalization may take a while, e.g. an executable has to deal with new deposits and old deposits at the same time. Another example may be economic constants. - Additional, backwards compatible: new constants are introduced for later phases. -- Changing: there is a very small chance some constant may really be *replaced*. +- Changing: there is a very small chance some constant may really be *replaced*. In this off-chance, it is likely better to include it as an additional variable, and some clients may simply stop supporting the old one if they do not want to sync from genesis. The change of functionality goes through a phase of deprecation of the old constant, and eventually only the new constant is kept around in the config (when old state is not supported anymore). @@ -157,7 +157,7 @@ Between all types of tests, a few formats are common: ##### `meta.yaml` -If present (it is optional), the test is enhanced with extra data to describe usage. Specialized data is described in the documentation of the specific test format. +If present (it is optional), the test is enhanced with extra data to describe usage. Specialized data is described in the documentation of the specific test format. Common data is documented here: @@ -205,7 +205,7 @@ The basic pattern for test-suite loading and running is: 1. For a specific config, load it first (and only need to do so once), then continue with the tests defined in the config folder. -2. Select a fork. Repeat for each fork if running tests for multiple forks. +2. Select a fork. Repeat for each fork if running tests for multiple forks. 3. Select the category and specialization of interest (e.g. `operations > deposits`). Again, repeat for each if running all. 4. Select a test suite. Or repeat for each. 5. Select a test case. Or repeat for each. @@ -213,4 +213,4 @@ The basic pattern for test-suite loading and running is: 7. Run the test, as defined by the test format. Step 1 may be a step with compile time selection of a configuration, if desired for optimization. -The base requirement is just to use the same set of constants, independent of the loading process. +The base requirement is just to use the same set of constants, independent of the loading process. diff --git a/tests/formats/epoch_processing/README.md b/tests/formats/epoch_processing/README.md index 0f6642141a..652cae0e91 100644 --- a/tests/formats/epoch_processing/README.md +++ b/tests/formats/epoch_processing/README.md @@ -25,7 +25,7 @@ An SSZ-snappy encoded `BeaconState`, the state after applying the epoch sub-tran ## Condition -A handler of the `epoch_processing` test-runner should process these cases, +A handler of the `epoch_processing` test-runner should process these cases, calling the corresponding processing implementation (same name, prefixed with `process_`). This excludes the other parts of the epoch-transition. The provided pre-state is already transitioned to just before the specific sub-transition of focus of the handler. diff --git a/tests/formats/fork_choice/README.md b/tests/formats/fork_choice/README.md index 1258a66c06..8a3e16a2d8 100644 --- a/tests/formats/fork_choice/README.md +++ b/tests/formats/fork_choice/README.md @@ -90,7 +90,7 @@ The parameter that is required for executing `on_block(store, block)`. proofs: array of byte48 hex string -- optional, the proofs of blob commitments. valid: bool -- optional, default to `true`. If it's `false`, this execution step is expected to be invalid. -} +} ``` The file is located in the same folder (see below). diff --git a/tests/formats/rewards/README.md b/tests/formats/rewards/README.md index a6682042f7..c7f3a9581b 100644 --- a/tests/formats/rewards/README.md +++ b/tests/formats/rewards/README.md @@ -49,7 +49,7 @@ An SSZ-snappy encoded `Deltas` representing the rewards and penalties returned b ## Condition -A handler of the `rewards` test-runner should process these cases, +A handler of the `rewards` test-runner should process these cases, calling the corresponding rewards deltas function for each set of deltas. The provided pre-state is ready to be input into each rewards deltas function. diff --git a/tests/formats/shuffling/README.md b/tests/formats/shuffling/README.md index 15bfe6996b..89d64e24de 100644 --- a/tests/formats/shuffling/README.md +++ b/tests/formats/shuffling/README.md @@ -35,4 +35,4 @@ I.e. `mapping[i]` is the shuffled location of `i`. ## Condition The resulting list should match the expected output after shuffling the implied input, using the given `seed`. -The output is checked using the `mapping`, based on the shuffling test type (e.g. can be backwards shuffling). +The output is checked using the `mapping`, based on the shuffling test type (e.g. can be backwards shuffling). diff --git a/tests/formats/ssz_generic/README.md b/tests/formats/ssz_generic/README.md index c46025847a..3545ab28c9 100644 --- a/tests/formats/ssz_generic/README.md +++ b/tests/formats/ssz_generic/README.md @@ -59,7 +59,7 @@ The object, encoded as a YAML structure. Using the same familiar encoding as YAM The conditions are the same for each type: - Encoding: After encoding the given `value` object, the output should match `serialized`. -- Decoding: After decoding the given `serialized` bytes, it should match the `value` object. +- Decoding: After decoding the given `serialized` bytes, it should match the `value` object. - Hash-tree-root: the root should match the root declared in the metadata. ## `invalid` diff --git a/tests/formats/ssz_static/core.md b/tests/formats/ssz_static/core.md index 09ff04e20d..a198bbcaff 100644 --- a/tests/formats/ssz_static/core.md +++ b/tests/formats/ssz_static/core.md @@ -42,7 +42,7 @@ A test-runner can implement the following assertions: - Serialization: After parsing the `value`, SSZ-serialize it: the output should match `serialized` - Deserialization: SSZ-deserialize the `serialized` value, and see if it matches the parsed `value` - If YAML decoding of SSZ objects is not supported by the implementation: - - Serialization in 2 steps: deserialize `serialized`, then serialize the result, + - Serialization in 2 steps: deserialize `serialized`, then serialize the result, and verify if the bytes match the original `serialized`. - Hash-tree-root: After parsing the `value` (or deserializing `serialized`), Hash-tree-root it: the output should match `root` diff --git a/tests/generators/README.md b/tests/generators/README.md index 0146ca35e8..536f0904c9 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -7,7 +7,7 @@ Any issues with the generators and/or generated tests should be filed in the rep On releases, test generators are run by the release manager. Test-generation of mainnet tests can take a significant amount of time, and is better left out of a CI setup. -An automated nightly tests release system, with a config filter applied, is being considered as implementation needs mature. +An automated nightly tests release system, with a config filter applied, is being considered as implementation needs mature. ## Table of contents @@ -39,7 +39,7 @@ Prerequisites: This removes the existing virtual environments (`/tests/generators//venv`) and generated tests (`../consensus-spec-tests/tests`). ```bash -make clean +make clean ``` ### Running all test generators @@ -195,9 +195,9 @@ Recommendations: - You can have more than just one test provider. - Your test provider is free to output any configuration and combination of runner/handler/fork/case name. - You can split your test case generators into different Python files/packages; this is good for code organization. -- Use config `minimal` for performance and simplicity, but also implement a suite with the `mainnet` config where necessary. +- Use config `minimal` for performance and simplicity, but also implement a suite with the `mainnet` config where necessary. - You may be able to write your test case provider in a way where it does not make assumptions on constants. - If so, you can generate test cases with different configurations for the same scenario (see example). + If so, you can generate test cases with different configurations for the same scenario (see example). - See [`tests/core/gen_helpers/README.md`](../core/pyspec/eth2spec/gen_helpers/README.md) for command line options for generators. ## How to add a new test generator diff --git a/tests/generators/epoch_processing/README.md b/tests/generators/epoch_processing/README.md index 662b0b516d..c572993d23 100644 --- a/tests/generators/epoch_processing/README.md +++ b/tests/generators/epoch_processing/README.md @@ -7,5 +7,5 @@ An epoch-processing test-runner can consume these sub-transition test-suites, Information on the format of the tests can be found in the [epoch-processing test formats documentation](../../formats/epoch_processing/README.md). - + diff --git a/tests/generators/operations/README.md b/tests/generators/operations/README.md index a5d48c11b4..234bb92a82 100644 --- a/tests/generators/operations/README.md +++ b/tests/generators/operations/README.md @@ -8,5 +8,5 @@ An operation test-runner can consume these operation test-suites, Information on the format of the tests can be found in the [operations test formats documentation](../../formats/operations/README.md). - + diff --git a/tests/generators/sanity/README.md b/tests/generators/sanity/README.md index cbc6aef06d..61979976db 100644 --- a/tests/generators/sanity/README.md +++ b/tests/generators/sanity/README.md @@ -4,5 +4,5 @@ Sanity tests cover regular state-transitions in a common block-list format, to e Information on the format of the tests can be found in the [sanity test formats documentation](../../formats/sanity/README.md). - + From f30d7bee0abfaaf6dfc7cd6d6a62622609ebe249 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 11 Oct 2024 07:56:23 -0500 Subject: [PATCH 009/141] Delete trailing whitespace for yaml files --- .github/workflows/docs.yml | 2 +- mkdocs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 209bb4a800..b7bfb3538a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,7 +3,7 @@ name: Publish docs on: push: branches: - - master + - master permissions: contents: write jobs: diff --git a/mkdocs.yml b/mkdocs.yml index dc6b352baa..3a9d76f8c1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,7 +7,7 @@ theme: - scheme: default primary: black toggle: - icon: material/brightness-7 + icon: material/brightness-7 name: Switch to dark mode - scheme: slate primary: black From 6f7248987042876d3e8783d3446f0a12cf18163a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 11 Oct 2024 07:59:31 -0500 Subject: [PATCH 010/141] Delete trailing whitespace from presets --- presets/mainnet/eip6800.yaml | 2 +- presets/minimal/eip6800.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/presets/mainnet/eip6800.yaml b/presets/mainnet/eip6800.yaml index d74ee62122..2282d8f960 100644 --- a/presets/mainnet/eip6800.yaml +++ b/presets/mainnet/eip6800.yaml @@ -2,7 +2,7 @@ # Misc # --------------------------------------------------------------- -# `uint64(2**16)` (= 65,536) +# `uint64(2**16)` (= 65,536) MAX_STEMS: 65536 # `uint64(33)` MAX_COMMITMENTS_PER_STEM: 33 diff --git a/presets/minimal/eip6800.yaml b/presets/minimal/eip6800.yaml index 499721e4a3..25e6e19c66 100644 --- a/presets/minimal/eip6800.yaml +++ b/presets/minimal/eip6800.yaml @@ -2,7 +2,7 @@ # Execution # --------------------------------------------------------------- -# `uint64(2**16)` (= 65,536) +# `uint64(2**16)` (= 65,536) MAX_STEMS: 65536 # `uint64(33)` MAX_COMMITMENTS_PER_STEM: 33 From 959d592df0966c285d0b8db7005f18114a9fbba6 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 11 Oct 2024 08:06:39 -0500 Subject: [PATCH 011/141] Add CI check for trailing whitespace --- .github/workflows/run-tests.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 83926c47c5..d0dee7a150 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -69,6 +69,18 @@ jobs: - name: Run linter for test generators run: make lint_generators + whitespace: + runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Check for trailing whitespace + run: | + if git grep -n '[[:blank:]]$'; then + echo "Trailing whitespace found. Please fix it." + exit 1 + fi + pyspec-tests: runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] needs: [lint,codespell,table_of_contents] From 2445bf519432b7aa01da832547ec51a1aaa1d19c Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 10:33:54 -0500 Subject: [PATCH 012/141] Move p2p-interface intros to introduction section --- specs/_features/das/p2p-interface.md | 18 ++++----- specs/_features/eip7594/p2p-interface.md | 7 ++++ specs/_features/eip7732/p2p-interface.md | 47 +++++++++++++----------- specs/altair/p2p-interface.md | 16 ++++---- specs/bellatrix/p2p-interface.md | 17 +++++---- specs/capella/p2p-interface.md | 10 +++-- specs/deneb/p2p-interface.md | 11 ++++-- specs/electra/p2p-interface.md | 11 ++++-- specs/phase0/p2p-interface.md | 21 ++++++----- 9 files changed, 92 insertions(+), 66 deletions(-) diff --git a/specs/_features/das/p2p-interface.md b/specs/_features/das/p2p-interface.md index b166c9c3e4..2c165078d2 100644 --- a/specs/_features/das/p2p-interface.md +++ b/specs/_features/das/p2p-interface.md @@ -28,12 +28,10 @@ - - ## Introduction For an introduction about DAS itself, see [the DAS participation spec](sampling.md#data-availability-sampling). -This is not a pre-requisite for the network layer, but will give you valuable context. +This is not a pre-requisite for the network layer, but will give you valuable context. For sampling, all nodes need to query for `k` random samples each slot. @@ -55,13 +53,13 @@ The push model does not aim to serve "historical" queries (anything older than t Historical queries are still required for the unhappy case, where messages are not pushed quick enough, and missing samples are not reconstructed by other nodes on the horizontal subnet quick enough. -The main challenge in supporting historical queries is to target the right nodes, +The main challenge in supporting historical queries is to target the right nodes, without concentrating too many requests on a single node, or breaking the network/consensus identity separation. ## DAS Subnets On a high level, the push-model roles are divided into: -- Sources: create blobs of shard block data, and transformed into many tiny samples. +- Sources: create blobs of shard block data, and transformed into many tiny samples. - Sinks: continuously look for samples At full operation, the network has one proposer, per shard, per slot. @@ -93,15 +91,15 @@ Peers on the horizontal subnet are expected to at least perform regular propagat Nodes on this same subnet can replicate the sampling efficiently (including a proof for each sample), and distribute it to any vertical networks that are available to them. -Since the messages are content-addressed (instead of origin-stamped), -multiple publishers of the same samples on a vertical subnet do not hurt performance, +Since the messages are content-addressed (instead of origin-stamped), +multiple publishers of the same samples on a vertical subnet do not hurt performance, but actually improve it by shortcutting regular propagation on the vertical subnet, and thus lowering the latency to a sample. ### Vertical subnets Vertical subnets propagate the samples to every peer that is interested. -These interests are randomly sampled and rotate quickly: although not perfect, +These interests are randomly sampled and rotate quickly: although not perfect, sufficient to avoid any significant amount of nodes from being 100% predictable. As soon as a sample is missing after the expected propagation time window, @@ -166,7 +164,7 @@ The [DAS participation spec](sampling.md#horizontal-subnets) outlines when and w #### Vertical subnets: `das_sample_{subnet_index}` -Shard blob samples can be verified with just a 48 byte KZG proof (commitment quotient polynomial), +Shard blob samples can be verified with just a 48 byte KZG proof (commitment quotient polynomial), against the commitment to blob polynomial, specific to that `(shard, slot)` key. The following validations MUST pass before forwarding the `sample` on the vertical subnet. @@ -192,7 +190,7 @@ This is to serve other peers that may have missed it. To pull samples from nodes, in case of network instability when samples are unavailable, a new query method is added to the Req-Resp domain. -This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md). +This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md). Note that DAS networking uses a different protocol prefix: `/eth2/das/req` diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index c989711807..900d521ac2 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -8,6 +8,7 @@ +- [Introduction](#introduction) - [Modifications in EIP-7594](#modifications-in-eip-7594) - [Preset](#preset) - [Configuration](#configuration) @@ -36,6 +37,12 @@ +## Introduction + +This document contains the consensus-layer networking specification for EIP7594. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + ## Modifications in EIP-7594 ### Preset diff --git a/specs/_features/eip7732/p2p-interface.md b/specs/_features/eip7732/p2p-interface.md index d33dfaba31..df02cc2382 100644 --- a/specs/_features/eip7732/p2p-interface.md +++ b/specs/_features/eip7732/p2p-interface.md @@ -1,10 +1,9 @@ # EIP-7732 -- Networking -This document contains the consensus-layer networking specification for EIP7732. - +- [Introduction](#introduction) - [Modification in EIP-7732](#modification-in-eip-7732) - [Preset](#preset) - [Configuration](#configuration) @@ -28,6 +27,12 @@ This document contains the consensus-layer networking specification for EIP7732. +## Introduction + +This document contains the consensus-layer networking specification for EIP7732. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + ## Modification in EIP-7732 ### Preset @@ -67,7 +72,7 @@ class BlobSidecar(Container): ##### Modified `verify_blob_sidecar_inclusion_proof` -`verify_blob_sidecar_inclusion_proof` is modified in EIP-7732 to account for the fact that the KZG commitments are included in the `ExecutionPayloadEnvelope` and no longer in the beacon block body. +`verify_blob_sidecar_inclusion_proof` is modified in EIP-7732 to account for the fact that the KZG commitments are included in the `ExecutionPayloadEnvelope` and no longer in the beacon block body. ```python def verify_blob_sidecar_inclusion_proof(blob_sidecar: BlobSidecar) -> bool: @@ -121,7 +126,7 @@ EIP-7732 introduces new global topics for execution header, execution payload an [Modified in EIP-7732] -The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in [the Beacon Chain changes](./beacon-chain.md). +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in [the Beacon Chain changes](./beacon-chain.md). There are no new validations for this topic. However, all validations with regards to the `ExecutionPayload` are removed: @@ -137,7 +142,7 @@ There are no new validations for this topic. However, all validations with regar And instead the following validations are set in place with the alias `header = signed_execution_payload_header.message`: - If `execution_payload` verification of block's execution payload parent by an execution node **is complete**: - - [REJECT] The block's execution payload parent (defined by `header.parent_block_hash`) passes all validation. + - [REJECT] The block's execution payload parent (defined by `header.parent_block_hash`) passes all validation. - [REJECT] The block's parent (defined by `block.parent_root`) passes validation. ###### `execution_payload` @@ -148,12 +153,12 @@ The following validations MUST pass before forwarding the `signed_execution_payl - _[IGNORE]_ The envelope's block root `envelope.block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue payload for processing once the block is retrieved). - _[IGNORE]_ The node has not seen another valid `SignedExecutionPayloadEnvelope` for this block root from this builder. - -Let `block` be the block with `envelope.beacon_block_root`. + +Let `block` be the block with `envelope.beacon_block_root`. Let `header` alias `block.body.signed_execution_payload_header.message` (notice that this can be obtained from the `state.signed_execution_payload_header`) -- _[REJECT]_ `block` passes validation. -- _[REJECT]_ `envelope.builder_index == header.builder_index` -- if `envelope.payload_withheld == False` then +- _[REJECT]_ `block` passes validation. +- _[REJECT]_ `envelope.builder_index == header.builder_index` +- if `envelope.payload_withheld == False` then - _[REJECT]_ `payload.block_hash == header.block_hash` - _[REJECT]_ The builder signature, `signed_execution_payload_envelope.signature`, is valid with respect to the builder's public key. @@ -163,14 +168,14 @@ This topic is used to propagate signed payload attestation message. The following validations MUST pass before forwarding the `payload_attestation_message` on the network, assuming the alias `data = payload_attestation_message.data`: -- _[IGNORE]_ The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`. -- _[REJECT]_ The message's payload status is a valid status, i.e. `data.payload_status < PAYLOAD_INVALID_STATUS`. -- _[IGNORE]_ The `payload_attestation_message` is the first valid message received from the validator with index `payload_attestation_message.validate_index`. -- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). -- _[REJECT]_ The message's block `data.beacon_block_root` passes validation. -- _[REJECT]_ The message's validator index is within the payload committee in `get_ptc(state, data.slot)`. The `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice. -- _[REJECT]_ The message's signature of `payload_attestation_message.signature` is valid with respect to the validator index. - +- _[IGNORE]_ The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`. +- _[REJECT]_ The message's payload status is a valid status, i.e. `data.payload_status < PAYLOAD_INVALID_STATUS`. +- _[IGNORE]_ The `payload_attestation_message` is the first valid message received from the validator with index `payload_attestation_message.validate_index`. +- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). +- _[REJECT]_ The message's block `data.beacon_block_root` passes validation. +- _[REJECT]_ The message's validator index is within the payload committee in `get_ptc(state, data.slot)`. The `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice. +- _[REJECT]_ The message's signature of `payload_attestation_message.signature` is valid with respect to the validator index. + ###### `execution_payload_header` This topic is used to propagate signed bids as `SignedExecutionPayloadHeader`. @@ -182,8 +187,8 @@ The following validations MUST pass before forwarding the `signed_execution_payl - _[REJECT]_ The signed builder bid, `header.builder_index` is a valid, active, and non-slashed builder index in state. - _[IGNORE]_ The signed builder bid value, `header.value`, is less or equal than the builder's balance in state. i.e. `MIN_BUILDER_BALANCE + header.value < state.builder_balances[header.builder_index]`. - _[IGNORE]_ `header.parent_block_hash` is the block hash of a known execution payload in fork choice. -_ _[IGNORE]_ `header.parent_block_root` is the hash tree root of a known beacon block in fork choice. -- _[IGNORE]_ `header.slot` is the current slot or the next slot. +_ _[IGNORE]_ `header.parent_block_root` is the hash tree root of a known beacon block in fork choice. +- _[IGNORE]_ `header.slot` is the current slot or the next slot. - _[REJECT]_ The builder signature, `signed_execution_payload_header_envelope.signature`, is valid with respect to the `header_envelope.builder_index`. ### The Req/Resp domain @@ -220,7 +225,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | | `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | -| `EIP7732_FORK_VERSION` | `eip7732.SignedBeaconBlock` | +| `EIP7732_FORK_VERSION` | `eip7732.SignedBeaconBlock` | ##### BlobSidecarsByRoot v2 diff --git a/specs/altair/p2p-interface.md b/specs/altair/p2p-interface.md index 5b0c938df7..f70e4e9b15 100644 --- a/specs/altair/p2p-interface.md +++ b/specs/altair/p2p-interface.md @@ -1,18 +1,12 @@ # Altair -- Networking -This document contains the networking specification for Altair. -This document should be viewed as additive to the [document from Phase 0](../phase0/p2p-interface.md) and will be referred to as the "Phase 0 document" hereafter. -Readers should understand the Phase 0 document and use it as a basis to understand the changes outlined in this document. - -Altair adds new messages, topics and data to the Req-Resp, Gossip and Discovery domain. Some Phase 0 features will be deprecated, but not removed immediately. - - ## Table of contents +- [Introduction](#introduction) - [Modifications in Altair](#modifications-in-altair) - [MetaData](#metadata) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) @@ -39,6 +33,14 @@ Altair adds new messages, topics and data to the Req-Resp, Gossip and Discovery +## Introduction + +This document contains the networking specification for Altair. +This document should be viewed as additive to the [document from Phase 0](../phase0/p2p-interface.md) and will be referred to as the "Phase 0 document" hereafter. +Readers should understand the Phase 0 document and use it as a basis to understand the changes outlined in this document. + +Altair adds new messages, topics and data to the Req-Resp, Gossip and Discovery domain. Some Phase 0 features will be deprecated, but not removed immediately. + ## Modifications in Altair ### MetaData diff --git a/specs/bellatrix/p2p-interface.md b/specs/bellatrix/p2p-interface.md index 617f6f1fc7..1f4c815660 100644 --- a/specs/bellatrix/p2p-interface.md +++ b/specs/bellatrix/p2p-interface.md @@ -1,17 +1,12 @@ # Bellatrix -- Networking -This document contains the networking specification for the Bellatrix. - -The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. This document should be viewed as additive to the documents from [Phase 0](../phase0/p2p-interface.md) and from [Altair](../altair/p2p-interface.md) -and will be referred to as the "Phase 0 document" and "Altair document" respectively, hereafter. -Readers should understand the Phase 0 and Altair documents and use them as a basis to understand the changes outlined in this document. - ## Table of contents + - [Introduction](#introduction) - [Modifications in Bellatrix](#modifications-in-bellatrix) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) @@ -32,6 +27,14 @@ Readers should understand the Phase 0 and Altair documents and use them as a bas +## Introduction + +This document contains the networking specification for Bellatrix. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. This document should be viewed as additive to the documents from [Phase 0](../phase0/p2p-interface.md) and from [Altair](../altair/p2p-interface.md) +and will be referred to as the "Phase 0 document" and "Altair document" respectively, hereafter. +Readers should understand the Phase 0 and Altair documents and use them as a basis to understand the changes outlined in this document. + ## Modifications in Bellatrix ### The gossip domain: gossipsub @@ -146,7 +149,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: With the addition of `ExecutionPayload` to `BeaconBlock`s, there is a dynamic field -- `transactions` -- which can validly exceed the `GOSSIP_MAX_SIZE` limit (1 MiB) put in -place at Phase 0, so GOSSIP_MAX_SIZE has increased to 10 Mib on the network. +place at Phase 0, so GOSSIP_MAX_SIZE has increased to 10 Mib on the network. At the `GAS_LIMIT` (~30M) currently seen on mainnet in 2021, a single transaction filled entirely with data at a cost of 16 gas per byte can create a valid `ExecutionPayload` of ~2 MiB. Thus we need a size limit to at least account for diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index a71b6479f1..25b2fb3b99 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -1,15 +1,12 @@ # Capella -- Networking -This document contains the networking specification for Capella. - -The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. - ### Table of contents +- [Introduction](#introduction) - [Modifications in Capella](#modifications-in-capella) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) @@ -25,6 +22,11 @@ The specification of these changes continues in the same format as the network s +## Introduction + +This document contains the networking specification for Capella. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. ## Modifications in Capella diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 41e2fa9d3f..1c1bb56a00 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -1,15 +1,12 @@ # Deneb -- Networking -This document contains the consensus-layer networking specification for Deneb. - -The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. - ## Table of contents +- [Introduction](#introduction) - [Modifications in Deneb](#modifications-in-deneb) - [Constant](#constant) - [Preset](#preset) @@ -41,6 +38,12 @@ The specification of these changes continues in the same format as the network s +## Introduction + +This document contains the consensus-layer networking specification for Deneb. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + ## Modifications in Deneb ### Constant diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index fca877a8aa..494a4d9255 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -1,15 +1,12 @@ # Electra -- Networking -This document contains the consensus-layer networking specification for Electra. - -The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. - ## Table of contents +- [Introduction](#introduction) - [Modifications in Electra](#modifications-in-electra) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) @@ -21,6 +18,12 @@ The specification of these changes continues in the same format as the network s +## Introduction + +This document contains the consensus-layer networking specification for Electra. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + ## Modifications in Electra ### The gossip domain: gossipsub diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index bc29b9ad92..f531f9fd2f 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1,19 +1,11 @@ # Phase 0 -- Networking -This document contains the networking specification for Phase 0. - -It consists of four main sections: - -1. A specification of the network fundamentals. -2. A specification of the three network interaction *domains* of the proof-of-stake consensus layer: (a) the gossip domain, (b) the discovery domain, and (c) the Req/Resp domain. -3. The rationale and further explanation for the design choices made in the previous two sections. -4. An analysis of the maturity/state of the libp2p features required by this spec across the languages in which clients are being developed. - ## Table of contents +- [Introduction](#introduction) - [Network fundamentals](#network-fundamentals) - [Transport](#transport) - [Encryption and identification](#encryption-and-identification) @@ -114,6 +106,17 @@ It consists of four main sections: +## Introduction + +This document contains the networking specification for Phase 0. + +It consists of four main sections: + +1. A specification of the network fundamentals. +2. A specification of the three network interaction *domains* of the proof-of-stake consensus layer: (a) the gossip domain, (b) the discovery domain, and (c) the Req/Resp domain. +3. The rationale and further explanation for the design choices made in the previous two sections. +4. An analysis of the maturity/state of the libp2p features required by this spec across the languages in which clients are being developed. + ## Network fundamentals This section outlines the specification for the networking stack in Ethereum consensus-layer clients. From a6095bf498243dfd2619a996c5c9f9fcbf79cfdc Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 21 Oct 2024 13:00:10 +0200 Subject: [PATCH 013/141] Update specs/deneb/beacon-chain.md Co-authored-by: Justin Traglia <95511699+jtraglia@users.noreply.github.com> --- specs/deneb/beacon-chain.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 1b7a322c2f..98a4b05bda 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -293,9 +293,8 @@ def verify_and_notify_new_payload(self: ExecutionEngine, """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ - # [Modified in Deneb:EIP4788] execution_payload = new_payload_request.execution_payload - parent_beacon_block_root = new_payload_request.parent_beacon_block_root + parent_beacon_block_root = new_payload_request.parent_beacon_block_root # [Modified in Deneb:EIP4788] if b'' in execution_payload.transactions: return False From 44d5a1b49bffbddc79f9a49ca4245c7ef0e7c693 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 21 Oct 2024 13:01:30 +0200 Subject: [PATCH 014/141] Sync changes to Electra --- specs/electra/beacon-chain.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 0c56491907..89575d671c 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1015,6 +1015,9 @@ def verify_and_notify_new_payload(self: ExecutionEngine, parent_beacon_block_root = new_payload_request.parent_beacon_block_root execution_requests_list = get_execution_requests_list(new_payload_request.execution_requests) # [New in Electra] + if b'' in execution_payload.transactions: + return False + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False From 0f964b04d288433fdf096e223031bd3e73a09807 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 21 Oct 2024 08:43:25 -0500 Subject: [PATCH 015/141] Change "modified" to "new" --- specs/deneb/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 98a4b05bda..1025af7b61 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -294,7 +294,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ execution_payload = new_payload_request.execution_payload - parent_beacon_block_root = new_payload_request.parent_beacon_block_root # [Modified in Deneb:EIP4788] + parent_beacon_block_root = new_payload_request.parent_beacon_block_root # [New in Deneb:EIP4788] if b'' in execution_payload.transactions: return False From 6c635ee85420ad6b7480d7ac61c13cce4adf309a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Mon, 21 Oct 2024 09:23:20 -0500 Subject: [PATCH 016/141] Merge changes into existing engine API spec --- specs/electra/beacon-chain.md | 69 +++++------------------------------ 1 file changed, 10 insertions(+), 59 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 758ffc7a81..2e4b8bfb6c 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -65,11 +65,6 @@ - [New `compute_consolidation_epoch_and_update_churn`](#new-compute_consolidation_epoch_and_update_churn) - [Modified `slash_validator`](#modified-slash_validator) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Execution engine](#execution-engine) - - [Request data](#request-data) - - [Engine APIs](#engine-apis) - - [Modified `notify_new_payload`](#modified-notify_new_payload) - - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Epoch processing](#epoch-processing) - [Modified `process_epoch`](#modified-process_epoch) - [Modified `process_registry_updates`](#modified-process_registry_updates) @@ -757,54 +752,6 @@ def slash_validator(state: BeaconState, ## Beacon chain state transition function -### Execution engine - -#### Request data - -#### Engine APIs - -##### Modified `notify_new_payload` - -*Note*: The function `notify_new_payload` is modified to include the target number of blobs -allowed per block. - -```python -def notify_new_payload(self: ExecutionEngine, - execution_payload: ExecutionPayload, - parent_beacon_block_root: Root, - target_blobs_per_block: uint64) -> bool: - """ - Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. - """ - ... -``` - -##### Modified `verify_and_notify_new_payload` - -```python -def verify_and_notify_new_payload(self: ExecutionEngine, - new_payload_request: NewPayloadRequest) -> bool: - """ - Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. - """ - execution_payload = new_payload_request.execution_payload - parent_beacon_block_root = new_payload_request.parent_beacon_block_root - - if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): - return False - - if not self.is_valid_versioned_hashes(new_payload_request): - return False - - # [Modified in Electra] - if not self.notify_new_payload(execution_payload, - parent_beacon_block_root, - MAX_BLOBS_PER_BLOCK // 2): - return False - - return True -``` - ### Epoch processing #### Modified `process_epoch` @@ -1039,15 +986,17 @@ class NewPayloadRequest(object): ##### Modified `notify_new_payload` -*Note*: The function `notify_new_payload` is modified to include the additional `execution_requests` parameter in Electra. +*Note*: The function `notify_new_payload` is modified to include the additional +`execution_requests_list` and `target_blobs_per_block` parameters in Electra. ```python def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - execution_requests_list: Sequence[bytes]) -> bool: + execution_requests_list: Sequence[bytes], + target_blobs_per_block: uint64) -> bool: """ - Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` + Return ``True`` if and only if ``execution_payload`` and ``execution_requests_list`` are valid with respect to ``self.execution_state``. """ ... @@ -1055,8 +1004,8 @@ def notify_new_payload(self: ExecutionEngine, ##### Modified `verify_and_notify_new_payload` -*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameter `execution_requests` -when calling `notify_new_payload` in Electra. +*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameters +`execution_requests_list` and `target_blobs_per_block` when calling `notify_new_payload` in Electra. ```python def verify_and_notify_new_payload(self: ExecutionEngine, @@ -1067,6 +1016,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, execution_payload = new_payload_request.execution_payload parent_beacon_block_root = new_payload_request.parent_beacon_block_root execution_requests_list = get_execution_requests_list(new_payload_request.execution_requests) # [New in Electra] + target_blobs_per_block = MAX_BLOBS_PER_BLOCK // 2 # [New in Electra:EIP7742] if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False @@ -1078,7 +1028,8 @@ def verify_and_notify_new_payload(self: ExecutionEngine, if not self.notify_new_payload( execution_payload, parent_beacon_block_root, - execution_requests_list): + execution_requests_list, + target_blobs_per_block): return False return True From c57a90ab7bd83913f34a53c81081a5528dd04e9b Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Tue, 22 Oct 2024 07:37:16 -0500 Subject: [PATCH 017/141] Rename *_blob_count to *_blobs_per_block --- specs/electra/fork-choice.md | 4 ++-- specs/electra/validator.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index 8b61e124d1..92109ac1e4 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -33,6 +33,6 @@ class PayloadAttributes(object): suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root - target_blob_count: uint64 # [New in Electra] - maximum_blob_count: uint64 # [New in Electra] + target_blobs_per_block: uint64 # [New in Electra:EIP7742] + maximum_blobs_per_block: uint64 # [New in Electra:EIP7742] ``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 8fe5e6b068..cb52f4f0b9 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -176,8 +176,8 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blob_count=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra] - maximum_blob_count=MAX_BLOBS_PER_BLOCK, # [New in Electra] + target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra:EIP7742] + maximum_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From 9d762fedbaa520bddb0a08859630023e4e4e02b5 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 07:39:21 -0500 Subject: [PATCH 018/141] Update PayloadAttributes note --- specs/electra/fork-choice.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index 92109ac1e4..17347be7bb 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -23,7 +23,7 @@ This is the modification of the fork choice accompanying the Electra upgrade. ### Extended `PayloadAttributes` -`PayloadAttributes` is extended with the maximum number of blobs per block. +*Note*: `PayloadAttributes` is extended with the target/maximum number of blobs per block. ```python @dataclass From 04225d5cfaf94f7662bed30dcc274cc29b83383b Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 07:49:11 -0500 Subject: [PATCH 019/141] Pass new args to is_valid_block_hash too --- pysetup/spec_builders/electra.py | 4 +++- specs/electra/beacon-chain.md | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index 8479d2d54e..b7d6cb1dcf 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -47,7 +47,9 @@ def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadRespo def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload, - parent_beacon_block_root: Root) -> bool: + parent_beacon_block_root, + execution_requests_list: Sequence[bytes], + target_blobs_per_block: uint64) -> bool: return True def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 2e4b8bfb6c..1127120c68 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -984,6 +984,23 @@ class NewPayloadRequest(object): #### Engine APIs +##### Modified `is_valid_block_hash` + +*Note*: The function `is_valid_block_hash` is modified to include the additional +`execution_requests_list` and `target_blobs_per_block` parameters in Electra. + +```python +def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root, + execution_requests_list: Sequence[bytes], + target_blobs_per_block: uint64) -> bool: + """ + Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly. + """ + ... +``` + ##### Modified `notify_new_payload` *Note*: The function `notify_new_payload` is modified to include the additional @@ -1005,7 +1022,8 @@ def notify_new_payload(self: ExecutionEngine, ##### Modified `verify_and_notify_new_payload` *Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameters -`execution_requests_list` and `target_blobs_per_block` when calling `notify_new_payload` in Electra. +`execution_requests_list` and `target_blobs_per_block` when calling `is_valid_block_hash` and +`notify_new_payload` in Electra. ```python def verify_and_notify_new_payload(self: ExecutionEngine, @@ -1018,7 +1036,12 @@ def verify_and_notify_new_payload(self: ExecutionEngine, execution_requests_list = get_execution_requests_list(new_payload_request.execution_requests) # [New in Electra] target_blobs_per_block = MAX_BLOBS_PER_BLOCK // 2 # [New in Electra:EIP7742] - if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): + # [Modified in Electra] + if not self.is_valid_block_hash( + execution_payload, + parent_beacon_block_root, + execution_requests_list, + target_blobs_per_block): return False if not self.is_valid_versioned_hashes(new_payload_request): From 6209809862a1c6fc1d8c137093274360c532914b Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 07:52:28 -0500 Subject: [PATCH 020/141] Fix table of contents --- specs/electra/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 1127120c68..d837a2a561 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -77,6 +77,7 @@ - [Request data](#request-data) - [Modified `NewPayloadRequest`](#modified-newpayloadrequest) - [Engine APIs](#engine-apis) + - [Modified `is_valid_block_hash`](#modified-is_valid_block_hash) - [Modified `notify_new_payload`](#modified-notify_new_payload) - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) From 4da2cea7e3ce672b257e6ec36245635162a88c08 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 09:04:07 -0500 Subject: [PATCH 021/141] Fix mistake (missing type hint) --- pysetup/spec_builders/electra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index b7d6cb1dcf..43362e4102 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -47,7 +47,7 @@ def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadRespo def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload, - parent_beacon_block_root, + parent_beacon_block_root: Root, execution_requests_list: Sequence[bytes], target_blobs_per_block: uint64) -> bool: return True From 0c5a1362c983c7e49519b9a603e62f13c0b45963 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 14:42:13 -0500 Subject: [PATCH 022/141] Exclude empty requests in requests list --- specs/electra/beacon-chain.md | 24 +++- specs/electra/validator.md | 43 +++++-- .../unittests/test_execution_requests.py | 115 ++++++++++++++++++ 3 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 0c56491907..5f0f77a2b8 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -137,6 +137,14 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `COMPOUNDING_WITHDRAWAL_PREFIX` | `Bytes1('0x02')` | +### Execution layer triggered requests + +| Name | Value | +| - | - | +| `DEPOSIT_REQUEST_TYPE` | `Bytes1('0x00')` | +| `WITHDRAWAL_REQUEST_TYPE` | `Bytes1('0x01')` | +| `CONSOLIDATION_REQUEST_TYPE` | `Bytes1('0x02')` | + ## Preset ### Gwei values @@ -1146,11 +1154,17 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None: ```python def get_execution_requests_list(execution_requests: ExecutionRequests) -> Sequence[bytes]: - deposit_bytes = ssz_serialize(execution_requests.deposits) - withdrawal_bytes = ssz_serialize(execution_requests.withdrawals) - consolidation_bytes = ssz_serialize(execution_requests.consolidations) - - return [deposit_bytes, withdrawal_bytes, consolidation_bytes] + requests = [ + (DEPOSIT_REQUEST_TYPE, execution_requests.deposits), + (WITHDRAWAL_REQUEST_TYPE, execution_requests.withdrawals), + (CONSOLIDATION_REQUEST_TYPE, execution_requests.consolidations), + ] + + return [ + request_type + ssz_serialize(request_data) + for request_type, request_data in requests + if len(request_data) != 0 + ] ``` ##### Modified `process_execution_payload` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 553eeaa702..c896efe11b 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -189,18 +189,45 @@ def prepare_execution_payload(state: BeaconState, *[New in Electra]* -1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined -in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The index of each element in the array determines the type of request. +1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. There can only be one instance of each request type per execution requests. 2. Set `block.body.execution_requests = get_execution_requests(execution_requests)`, where: ```python def get_execution_requests(execution_requests: Sequence[bytes]) -> ExecutionRequests: - deposits = ssz_deserialize(List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], execution_requests[0]) - withdrawals = ssz_deserialize(List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], execution_requests[1]) - consolidations = ssz_deserialize(List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], - execution_requests[2]) - - return ExecutionRequests(deposits, withdrawals, consolidations) + deposits = None + withdrawals = None + consolidations = None + + for request in execution_requests: + request_type, request_data = request[0:1], request[1:] + assert len(request_data) != 0, "empty request data" + + if request_type == DEPOSIT_REQUEST_TYPE: + assert deposits is None, "duplicate deposit request" + deposits = ssz_deserialize( + List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], + request_data + ) + elif request_type == WITHDRAWAL_REQUEST_TYPE: + assert withdrawals is None, "duplicate withdrawal request" + withdrawals = ssz_deserialize( + List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], + request_data + ) + elif request_type == CONSOLIDATION_REQUEST_TYPE: + assert consolidations is None, "duplicate consolidation request" + consolidations = ssz_deserialize( + List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], + request_data + ) + else: + raise ValueError(f"unexpected request type: {repr(request_type)}") + + return ExecutionRequests( + deposits=deposits or [], + withdrawals=withdrawals or [], + consolidations=consolidations or [] + ) ``` ## Attesting diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py new file mode 100644 index 0000000000..581b1a54a8 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py @@ -0,0 +1,115 @@ +from eth2spec.test.context import ( + single_phase, + spec_test, + with_electra_and_later, +) + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_serialization_round_trip__empty(spec): + execution_requests = spec.ExecutionRequests() + serialized_execution_requests = spec.get_execution_requests_list(execution_requests) + deserialized_execution_requests = spec.get_execution_requests(serialized_execution_requests) + assert deserialized_execution_requests == execution_requests + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_serialization_round_trip__one_request(spec): + execution_requests = spec.ExecutionRequests( + deposits=[spec.DepositRequest()], + ) + serialized_execution_requests = spec.get_execution_requests_list(execution_requests) + deserialized_execution_requests = spec.get_execution_requests(serialized_execution_requests) + assert deserialized_execution_requests == execution_requests + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_serialization_round_trip__multiple_requests(spec): + execution_requests = spec.ExecutionRequests( + deposits=[spec.DepositRequest()], + withdrawals=[spec.WithdrawalRequest()], + consolidations=[spec.ConsolidationRequest()], + ) + serialized_execution_requests = spec.get_execution_requests_list(execution_requests) + deserialized_execution_requests = spec.get_execution_requests(serialized_execution_requests) + assert deserialized_execution_requests == execution_requests + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_serialization_round_trip__one_request_with_real_data(spec): + execution_requests = spec.ExecutionRequests( + deposits=[ + spec.DepositRequest( + pubkey=spec.BLSPubkey(48 * "aa"), + withdrawal_credentials=spec.Bytes32(32 * "bb"), + amount=spec.Gwei(11111111), + signature=spec.BLSSignature(96 * "cc"), + index=spec.uint64(22222222), + ), + ] + ) + serialized_execution_requests = spec.get_execution_requests_list(execution_requests) + deserialized_execution_requests = spec.get_execution_requests(serialized_execution_requests) + assert deserialized_execution_requests == execution_requests + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_deserialize__allow_out_of_order_requests(spec): + serialized_execution_requests = [ + spec.WITHDRAWAL_REQUEST_TYPE + 76 * b"\x0a", + spec.DEPOSIT_REQUEST_TYPE + 192 * b"\x0b", + ] + assert int(serialized_execution_requests[0][0]) > int(serialized_execution_requests[1][0]) + spec.get_execution_requests(serialized_execution_requests) + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_deserialize__reject_empty_request(spec): + serialized_execution_requests = [b"\x01"] + try: + spec.get_execution_requests(serialized_execution_requests) + assert False, "expected exception" + except Exception as e: + assert "empty request data" in str(e) + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_deserialize__reject_duplicate_request(spec): + serialized_withdrawal = 76 * b"\x0a" + serialized_execution_requests = [ + spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, + spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, + ] + try: + spec.get_execution_requests(serialized_execution_requests) + assert False, "expected exception" + except Exception as e: + assert "duplicate withdrawal request" in str(e) + + +@with_electra_and_later +@spec_test +@single_phase +def test_requests_deserialize__reject_unexpected_request_type(spec): + serialized_execution_requests = [ + b"\x03\xff\xff\xff", + ] + try: + spec.get_execution_requests(serialized_execution_requests) + assert False, "expected exception" + except Exception as e: + assert "unexpected request type" in str(e) From 369b7e578072aa3c6640351db39fd696a4fd484c Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 14:47:16 -0500 Subject: [PATCH 023/141] Fix table of contents --- specs/electra/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 5f0f77a2b8..940bba7b8b 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -12,6 +12,7 @@ - [Constants](#constants) - [Misc](#misc) - [Withdrawal prefixes](#withdrawal-prefixes) + - [Execution layer triggered requests](#execution-layer-triggered-requests) - [Preset](#preset) - [Gwei values](#gwei-values) - [Rewards and penalties](#rewards-and-penalties) From 2bd570c6be385d372ad877713e9d0c366b07ca2f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 14:58:21 -0500 Subject: [PATCH 024/141] Use assert instead of raise --- specs/electra/validator.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index c896efe11b..6b544f56e4 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -199,7 +199,13 @@ def get_execution_requests(execution_requests: Sequence[bytes]) -> ExecutionRequ consolidations = None for request in execution_requests: + assert len(request) >= 1 request_type, request_data = request[0:1], request[1:] + assert request_type in [ + DEPOSIT_REQUEST_TYPE, + WITHDRAWAL_REQUEST_TYPE, + CONSOLIDATION_REQUEST_TYPE, + ], f"unexpected request type: {repr(request_type)}" assert len(request_data) != 0, "empty request data" if request_type == DEPOSIT_REQUEST_TYPE: @@ -220,8 +226,6 @@ def get_execution_requests(execution_requests: Sequence[bytes]) -> ExecutionRequ List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], request_data ) - else: - raise ValueError(f"unexpected request type: {repr(request_type)}") return ExecutionRequests( deposits=deposits or [], From 8a8a3214cdaaedd6622329de1753d7484df46b4b Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 15:10:22 -0500 Subject: [PATCH 025/141] Fix indentation --- specs/electra/validator.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 6b544f56e4..028d4b659d 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -202,9 +202,9 @@ def get_execution_requests(execution_requests: Sequence[bytes]) -> ExecutionRequ assert len(request) >= 1 request_type, request_data = request[0:1], request[1:] assert request_type in [ - DEPOSIT_REQUEST_TYPE, - WITHDRAWAL_REQUEST_TYPE, - CONSOLIDATION_REQUEST_TYPE, + DEPOSIT_REQUEST_TYPE, + WITHDRAWAL_REQUEST_TYPE, + CONSOLIDATION_REQUEST_TYPE, ], f"unexpected request type: {repr(request_type)}" assert len(request_data) != 0, "empty request data" From 3ce29297ce1f954e006d60f926d9c16b008cce0f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 16:04:03 -0500 Subject: [PATCH 026/141] Simplify get_execution_requests --- specs/electra/validator.md | 63 ++++++++----------- .../unittests/test_execution_requests.py | 2 +- 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 028d4b659d..4348b0a320 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -193,45 +193,34 @@ def prepare_execution_payload(state: BeaconState, 2. Set `block.body.execution_requests = get_execution_requests(execution_requests)`, where: ```python -def get_execution_requests(execution_requests: Sequence[bytes]) -> ExecutionRequests: - deposits = None - withdrawals = None - consolidations = None - - for request in execution_requests: - assert len(request) >= 1 +def get_execution_requests(execution_requests_list: Sequence[bytes]) -> ExecutionRequests: + requests = { + DEPOSIT_REQUEST_TYPE: { + "value": None, + "field": "deposits", + "type": List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], + }, + WITHDRAWAL_REQUEST_TYPE: { + "value": None, + "field": "withdrawals", + "type": List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], + }, + CONSOLIDATION_REQUEST_TYPE: { + "value": None, + "field": "consolidations", + "type": List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], + }, + } + + execution_requests = ExecutionRequests() + for request in execution_requests_list: request_type, request_data = request[0:1], request[1:] - assert request_type in [ - DEPOSIT_REQUEST_TYPE, - WITHDRAWAL_REQUEST_TYPE, - CONSOLIDATION_REQUEST_TYPE, - ], f"unexpected request type: {repr(request_type)}" + assert request_type in requests, "unexpected request type" assert len(request_data) != 0, "empty request data" - - if request_type == DEPOSIT_REQUEST_TYPE: - assert deposits is None, "duplicate deposit request" - deposits = ssz_deserialize( - List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], - request_data - ) - elif request_type == WITHDRAWAL_REQUEST_TYPE: - assert withdrawals is None, "duplicate withdrawal request" - withdrawals = ssz_deserialize( - List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], - request_data - ) - elif request_type == CONSOLIDATION_REQUEST_TYPE: - assert consolidations is None, "duplicate consolidation request" - consolidations = ssz_deserialize( - List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], - request_data - ) - - return ExecutionRequests( - deposits=deposits or [], - withdrawals=withdrawals or [], - consolidations=consolidations or [] - ) + assert requests[request_type]["value"] is None, "duplicate request" + requests[request_type]["value"] = ssz_deserialize(requests[request_type]["type"], request_data) + setattr(execution_requests, requests[request_type]["field"], requests[request_type]["value"]) + return execution_requests ``` ## Attesting diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py index 581b1a54a8..1204ffce17 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py @@ -98,7 +98,7 @@ def test_requests_deserialize__reject_duplicate_request(spec): spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" except Exception as e: - assert "duplicate withdrawal request" in str(e) + assert "duplicate request" in str(e) @with_electra_and_later From 4438166552c25536ed6c7d90712dfb2e85fc7d22 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 29 Oct 2024 19:22:27 -0500 Subject: [PATCH 027/141] Check for ascending order --- specs/electra/validator.md | 13 ++++--- .../unittests/test_execution_requests.py | 34 +++++++++++-------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 4348b0a320..04e521ab84 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -189,37 +189,36 @@ def prepare_execution_payload(state: BeaconState, *[New in Electra]* -1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. There can only be one instance of each request type per execution requests. +1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. Requests must be order by request type in ascending order. As a result, there can only be one instance of each request type per execution requests. 2. Set `block.body.execution_requests = get_execution_requests(execution_requests)`, where: ```python def get_execution_requests(execution_requests_list: Sequence[bytes]) -> ExecutionRequests: requests = { DEPOSIT_REQUEST_TYPE: { - "value": None, "field": "deposits", "type": List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], }, WITHDRAWAL_REQUEST_TYPE: { - "value": None, "field": "withdrawals", "type": List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], }, CONSOLIDATION_REQUEST_TYPE: { - "value": None, "field": "consolidations", "type": List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], }, } + prev_request_type = None execution_requests = ExecutionRequests() for request in execution_requests_list: request_type, request_data = request[0:1], request[1:] assert request_type in requests, "unexpected request type" assert len(request_data) != 0, "empty request data" - assert requests[request_type]["value"] is None, "duplicate request" - requests[request_type]["value"] = ssz_deserialize(requests[request_type]["type"], request_data) - setattr(execution_requests, requests[request_type]["field"], requests[request_type]["value"]) + assert prev_request_type is None or prev_request_type < request_type, "not ascending order" + prev_request_type = request_type + deserialized_request = ssz_deserialize(requests[request_type]["type"], request_data) + setattr(execution_requests, requests[request_type]["field"], deserialized_request) return execution_requests ``` diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py index 1204ffce17..2a63c17a3f 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py @@ -64,41 +64,45 @@ def test_requests_serialization_round_trip__one_request_with_real_data(spec): @with_electra_and_later @spec_test @single_phase -def test_requests_deserialize__allow_out_of_order_requests(spec): +def test_requests_deserialize__reject_duplicate_request(spec): + serialized_withdrawal = 76 * b"\x0a" serialized_execution_requests = [ - spec.WITHDRAWAL_REQUEST_TYPE + 76 * b"\x0a", - spec.DEPOSIT_REQUEST_TYPE + 192 * b"\x0b", + spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, + spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, ] - assert int(serialized_execution_requests[0][0]) > int(serialized_execution_requests[1][0]) - spec.get_execution_requests(serialized_execution_requests) + try: + spec.get_execution_requests(serialized_execution_requests) + assert False, "expected exception" + except Exception as e: + assert "not ascending order" in str(e) @with_electra_and_later @spec_test @single_phase -def test_requests_deserialize__reject_empty_request(spec): - serialized_execution_requests = [b"\x01"] +def test_requests_deserialize__reject_out_of_order_requests(spec): + serialized_execution_requests = [ + spec.WITHDRAWAL_REQUEST_TYPE + 76 * b"\x0a", + spec.DEPOSIT_REQUEST_TYPE + 192 * b"\x0b", + ] + assert int(serialized_execution_requests[0][0]) > int(serialized_execution_requests[1][0]) try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" except Exception as e: - assert "empty request data" in str(e) + assert "not ascending order" in str(e) @with_electra_and_later @spec_test @single_phase -def test_requests_deserialize__reject_duplicate_request(spec): - serialized_withdrawal = 76 * b"\x0a" - serialized_execution_requests = [ - spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, - spec.WITHDRAWAL_REQUEST_TYPE + serialized_withdrawal, - ] +def test_requests_deserialize__reject_empty_request(spec): + serialized_execution_requests = [b"\x01"] try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" except Exception as e: - assert "duplicate request" in str(e) + assert "empty request data" in str(e) @with_electra_and_later From e90c792c5cf4412f6885f48f6a639a53ac570522 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:51:49 -0500 Subject: [PATCH 028/141] Fix typo Co-authored-by: Alex Stokes --- specs/electra/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 04e521ab84..b79c262507 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -189,7 +189,7 @@ def prepare_execution_payload(state: BeaconState, *[New in Electra]* -1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. Requests must be order by request type in ascending order. As a result, there can only be one instance of each request type per execution requests. +1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. Requests must be ordered by request type in ascending order. As a result, there can only be one instance of each request type per execution requests. 2. Set `block.body.execution_requests = get_execution_requests(execution_requests)`, where: ```python From b3e77d2f575d9a03a3afd13269cfb6ca421cef78 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 30 Oct 2024 15:55:41 -0500 Subject: [PATCH 029/141] Apply other stokes suggestion --- specs/electra/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index b79c262507..55f9f10273 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -189,7 +189,7 @@ def prepare_execution_payload(state: BeaconState, *[New in Electra]* -1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. Requests must be ordered by request type in ascending order. As a result, there can only be one instance of each request type per execution requests. +1. The execution payload is obtained from the execution engine as defined above using `payload_id`. The response also includes a `execution_requests` entry containing a list of bytes. Each element on the list corresponds to one SSZ list of requests as defined in [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). The first byte of each request is used to determine the request type. Requests must be ordered by request type in ascending order. As a result, there can only be at most one instance of each request type. 2. Set `block.body.execution_requests = get_execution_requests(execution_requests)`, where: ```python From 276c56201a56d9e343f500db13d4b8dd4482a1f7 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 30 Oct 2024 16:47:53 -0500 Subject: [PATCH 030/141] Use less python sugar --- specs/electra/validator.md | 51 ++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 55f9f10273..1cd4b91eca 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -194,32 +194,45 @@ def prepare_execution_payload(state: BeaconState, ```python def get_execution_requests(execution_requests_list: Sequence[bytes]) -> ExecutionRequests: - requests = { - DEPOSIT_REQUEST_TYPE: { - "field": "deposits", - "type": List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], - }, - WITHDRAWAL_REQUEST_TYPE: { - "field": "withdrawals", - "type": List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], - }, - CONSOLIDATION_REQUEST_TYPE: { - "field": "consolidations", - "type": List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], - }, - } + deposits = [] + withdrawals = [] + consolidations = [] + + request_types = [ + DEPOSIT_REQUEST_TYPE, + WITHDRAWAL_REQUEST_TYPE, + CONSOLIDATION_REQUEST_TYPE, + ] prev_request_type = None - execution_requests = ExecutionRequests() for request in execution_requests_list: request_type, request_data = request[0:1], request[1:] - assert request_type in requests, "unexpected request type" + assert request_type in request_types, "unexpected request type" assert len(request_data) != 0, "empty request data" assert prev_request_type is None or prev_request_type < request_type, "not ascending order" prev_request_type = request_type - deserialized_request = ssz_deserialize(requests[request_type]["type"], request_data) - setattr(execution_requests, requests[request_type]["field"], deserialized_request) - return execution_requests + + if request_type == DEPOSIT_REQUEST_TYPE: + deposits = ssz_deserialize( + List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], + request_data + ) + elif request_type == WITHDRAWAL_REQUEST_TYPE: + withdrawals = ssz_deserialize( + List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], + request_data + ) + elif request_type == CONSOLIDATION_REQUEST_TYPE: + consolidations = ssz_deserialize( + List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], + request_data + ) + + return ExecutionRequests( + deposits=deposits, + withdrawals=withdrawals, + consolidations=consolidations, + ) ``` ## Attesting From e3eb09b71604374a253025f80598d27f5bd88508 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 31 Oct 2024 10:06:32 -0500 Subject: [PATCH 031/141] Rename maximum_blobs_per_block to max_blobs_per_block --- specs/electra/fork-choice.md | 2 +- specs/electra/validator.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index 17347be7bb..8530239325 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -34,5 +34,5 @@ class PayloadAttributes(object): withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root target_blobs_per_block: uint64 # [New in Electra:EIP7742] - maximum_blobs_per_block: uint64 # [New in Electra:EIP7742] + max_blobs_per_block: uint64 # [New in Electra:EIP7742] ``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index cb52f4f0b9..de0bdb4de1 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -177,7 +177,7 @@ def prepare_execution_payload(state: BeaconState, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra:EIP7742] - maximum_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] + max_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From a3d4dbaafaa5a3eb3a88cab11be8e903573f4346 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 4 Nov 2024 17:40:10 +0600 Subject: [PATCH 032/141] Ensure non-zero bits for each aggregate committee --- specs/electra/beacon-chain.md | 37 +++++++++++++++++-- .../test_process_attestation.py | 32 ++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 3e12ab2171..f6743e967e 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -56,6 +56,7 @@ - [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit) - [New `get_consolidation_churn_limit`](#new-get_consolidation_churn_limit) - [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw) + - [Modified `get_indexed_attestation`](#modified-get_indexed_attestation) - [Modified `get_attesting_indices`](#modified-get_attesting_indices) - [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices) - [Beacon state mutators](#beacon-state-mutators) @@ -572,6 +573,25 @@ def get_pending_balance_to_withdraw(state: BeaconState, validator_index: Validat ) ``` +#### Modified `get_indexed_attestation` + +*Note*: The function is modified to use the new `get_attesting_indices`. + +```python +def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation: + """ + Return the indexed attestation corresponding to ``attestation``. + """ + # [Modified in Electra:EIP7549] + attesting_indices = get_attesting_indices(state, attestation) + + return IndexedAttestation( + attesting_indices=sorted(attesting_indices), + data=attestation.data, + signature=attestation.signature, + ) +``` + #### Modified `get_attesting_indices` *Note*: The function `get_attesting_indices` is modified to support EIP7549. @@ -1254,6 +1274,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: ###### Modified `process_attestation` +*Note*: The function is modified to support EIP7549. + ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: data = attestation.data @@ -1264,18 +1286,24 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: # [Modified in Electra:EIP7549] assert data.index == 0 committee_indices = get_committee_indices(attestation.committee_bits) - participants_count = 0 + committee_offset = 0 for index in committee_indices: assert index < get_committee_count_per_slot(state, data.target.epoch) committee = get_beacon_committee(state, data.slot, index) - participants_count += len(committee) + committee_attesters = set( + attester_index for i, attester_index in enumerate(committee) + if attestation.aggregation_bits[committee_offset + i] + ) + assert len(committee_attesters) > 0 + committee_offset += len(committee) - assert len(attestation.aggregation_bits) == participants_count + # Bitfield length matches total number of participants + assert len(attestation.aggregation_bits) == committee_offset # Participation flag indices participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) - # Verify signature + # Verify signature [Modified in Electra:EIP7549] assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) # Update epoch participation flags @@ -1285,6 +1313,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: epoch_participation = state.previous_epoch_participation proposer_reward_numerator = 0 + # [Modified in Electra:EIP7549] for index in get_attesting_indices(state, attestation): for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py index f268feb034..f8d54b37f5 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py @@ -1,12 +1,15 @@ +from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( always_bls, spec_state_test, with_electra_and_later, + with_presets, ) from eth2spec.test.helpers.attestations import ( run_attestation_processing, get_valid_attestation, sign_attestation, + get_empty_eip7549_aggregation_bits, ) from eth2spec.test.helpers.state import ( next_slots, @@ -79,3 +82,32 @@ def test_invalid_nonset_committe_bits(spec, state): attestation.committee_bits[committee_index] = 0 yield from run_attestation_processing(spec, state, attestation, valid=False) + + +@with_electra_and_later +@spec_state_test +def test_invalid_nonset_bits_for_one_committee(spec, state): + """ + EIP-7549 test + """ + # Attestation with full committee participating + committee_0 = spec.get_beacon_committee(state, state.slot, 0) + attestation_1 = get_valid_attestation(spec, state, index=1, signed=True) + + # Create an on chain aggregate + aggregate = spec.Attestation(data=attestation_1.data, signature=attestation_1.signature) + aggregate.committee_bits[0] = True + aggregate.committee_bits[1] = True + aggregate.aggregation_bits = get_empty_eip7549_aggregation_bits( + spec, state, aggregate.committee_bits, aggregate.data.slot + ) + committee_offset = len(committee_0) + for i in range(len(attestation_1.aggregation_bits)): + aggregate.aggregation_bits[committee_offset + i] = attestation_1.aggregation_bits[i] + + # Check that only one committee is presented + assert spec.get_attesting_indices(state, aggregate) == spec.get_attesting_indices(state, attestation_1) + + next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY) + + yield from run_attestation_processing(spec, state, aggregate, valid=False) From 2222c24eeb0ab253fb0c9739e378479987ee03b4 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 4 Nov 2024 18:58:09 +0600 Subject: [PATCH 033/141] Run multiple committee tests with MINIMAL presets --- .../test/electra/block_processing/test_process_attestation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py index f8d54b37f5..7102a46f8e 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_attestation.py @@ -86,6 +86,7 @@ def test_invalid_nonset_committe_bits(spec, state): @with_electra_and_later @spec_state_test +@with_presets([MINIMAL], "need multiple committees per slot") def test_invalid_nonset_bits_for_one_committee(spec, state): """ EIP-7549 test From 1afabf7a0b05e20cdaebf5bf8658c265fdccc55b Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Tue, 5 Nov 2024 11:31:39 +0600 Subject: [PATCH 034/141] Rename index to committee_index in process_attestation --- specs/electra/beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 306e304a78..861d8f0059 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1288,9 +1288,9 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: assert data.index == 0 committee_indices = get_committee_indices(attestation.committee_bits) committee_offset = 0 - for index in committee_indices: - assert index < get_committee_count_per_slot(state, data.target.epoch) - committee = get_beacon_committee(state, data.slot, index) + for committee_index in committee_indices: + assert committee_index < get_committee_count_per_slot(state, data.target.epoch) + committee = get_beacon_committee(state, data.slot, committee_index) committee_attesters = set( attester_index for i, attester_index in enumerate(committee) if attestation.aggregation_bits[committee_offset + i] From ebbce03db569b81df9eefc2f7832252081b45690 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 6 Nov 2024 13:26:59 -0600 Subject: [PATCH 035/141] Replace assert messages with comments --- specs/electra/validator.md | 11 ++++++++--- .../electra/unittests/test_execution_requests.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 1cd4b91eca..ca92a1d955 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -207,9 +207,14 @@ def get_execution_requests(execution_requests_list: Sequence[bytes]) -> Executio prev_request_type = None for request in execution_requests_list: request_type, request_data = request[0:1], request[1:] - assert request_type in request_types, "unexpected request type" - assert len(request_data) != 0, "empty request data" - assert prev_request_type is None or prev_request_type < request_type, "not ascending order" + + # Check that the request type is valid + assert request_type in request_types + # Check that the request data is not empty + assert len(request_data) != 0 + # Check that requests are in strictly ascending order + # Each successive type must be greater than the last with no duplicates + assert prev_request_type is None or prev_request_type < request_type prev_request_type = request_type if request_type == DEPOSIT_REQUEST_TYPE: diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py index 2a63c17a3f..d57e724312 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_execution_requests.py @@ -73,8 +73,8 @@ def test_requests_deserialize__reject_duplicate_request(spec): try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" - except Exception as e: - assert "not ascending order" in str(e) + except Exception: + pass @with_electra_and_later @@ -89,8 +89,8 @@ def test_requests_deserialize__reject_out_of_order_requests(spec): try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" - except Exception as e: - assert "not ascending order" in str(e) + except Exception: + pass @with_electra_and_later @@ -101,8 +101,8 @@ def test_requests_deserialize__reject_empty_request(spec): try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" - except Exception as e: - assert "empty request data" in str(e) + except Exception: + pass @with_electra_and_later @@ -115,5 +115,5 @@ def test_requests_deserialize__reject_unexpected_request_type(spec): try: spec.get_execution_requests(serialized_execution_requests) assert False, "expected exception" - except Exception as e: - assert "unexpected request type" in str(e) + except Exception: + pass From ec01912af6c5f74e835b2cdd83a8976ad2e268fe Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 6 Nov 2024 14:31:26 -0600 Subject: [PATCH 036/141] Fix some nits in the constants/presets sections --- specs/electra/beacon-chain.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 62b50985af..121fd71585 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -129,8 +129,8 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | -| `UNSET_DEPOSIT_REQUESTS_START_INDEX` | `uint64(2**64 - 1)` | *[New in Electra:EIP6110]* | -| `FULL_EXIT_REQUEST_AMOUNT` | `uint64(0)` | *[New in Electra:EIP7002]* | +| `UNSET_DEPOSIT_REQUESTS_START_INDEX` | `uint64(2**64 - 1)` | *[New in Electra:EIP6110]* Value which indicates no start index has been assigned | +| `FULL_EXIT_REQUEST_AMOUNT` | `uint64(0)` | *[New in Electra:EIP7002]* Withdrawal amount used to signal a full validator exit | ### Withdrawal prefixes @@ -144,15 +144,15 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | | - | - | -| `MIN_ACTIVATION_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | +| `MIN_ACTIVATION_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | | `MAX_EFFECTIVE_BALANCE_ELECTRA` | `Gwei(2**11 * 10**9)` (= 2048,000,000,000) | ### Rewards and penalties | Name | Value | | - | - | -| `MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA` | `uint64(2**12)` (= 4,096) | -| `WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA` | `uint64(2**12)` (= 4,096) | +| `MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA` | `uint64(2**12)` (= 4,096) | +| `WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA` | `uint64(2**12)` (= 4,096) | ### State list lengths @@ -166,14 +166,14 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | | - | - | -| `MAX_ATTESTER_SLASHINGS_ELECTRA` | `2**0` (= 1) | *[New in Electra:EIP7549]* | -| `MAX_ATTESTATIONS_ELECTRA` | `2**3` (= 8) | *[New in Electra:EIP7549]* | +| `MAX_ATTESTER_SLASHINGS_ELECTRA` | `2**0` (= 1) | +| `MAX_ATTESTATIONS_ELECTRA` | `2**3` (= 8) | ### Execution | Name | Value | Description | | - | - | - | -| `MAX_DEPOSIT_REQUESTS_PER_PAYLOAD` | `uint64(2**13)` (= 8,192) | *[New in Electra:EIP6110]* Maximum number of deposit receipts allowed in each payload | +| `MAX_DEPOSIT_REQUESTS_PER_PAYLOAD` | `uint64(2**13)` (= 8,192) | *[New in Electra:EIP6110]* Maximum number of execution layer deposit requests in each payload | | `MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD` | `uint64(2**4)` (= 16)| *[New in Electra:EIP7002]* Maximum number of execution layer withdrawal requests in each payload | | `MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD` | `uint64(1)` (= 1) | *[New in Electra:EIP7251]* Maximum number of execution layer consolidation requests in each payload | From 7930bb6bd9c57c14bd8c22813e9abdb2bda6feed Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 6 Nov 2024 14:48:31 -0600 Subject: [PATCH 037/141] Add descriptions for new prefix & gwei values --- specs/electra/beacon-chain.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 121fd71585..7bbb7ef14d 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -134,18 +134,18 @@ The following values are (non-configurable) constants used throughout the specif ### Withdrawal prefixes -| Name | Value | -| - | - | -| `COMPOUNDING_WITHDRAWAL_PREFIX` | `Bytes1('0x02')` | +| Name | Value | Description | +| - | - | - | +| `COMPOUNDING_WITHDRAWAL_PREFIX` | `Bytes1('0x02')` | *[New in Electra:EIP7251]* Withdrawal credential prefix for a compounding validator | ## Preset ### Gwei values -| Name | Value | -| - | - | -| `MIN_ACTIVATION_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | -| `MAX_EFFECTIVE_BALANCE_ELECTRA` | `Gwei(2**11 * 10**9)` (= 2048,000,000,000) | +| Name | Value | Description | +| - | - | - | +| `MIN_ACTIVATION_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | *[New in Electra:EIP7251]* Minimum balance for a validator to become active | +| `MAX_EFFECTIVE_BALANCE_ELECTRA` | `Gwei(2**11 * 10**9)` (= 2048,000,000,000) | *[New in Electra:EIP7251]* Maximum balance for a compounding validator | ### Rewards and penalties From f024665275a681b34803939c8f54a04db4e7f01f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 6 Nov 2024 14:51:24 -0600 Subject: [PATCH 038/141] Clarify that it's the effective balance --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 7bbb7ef14d..290694087d 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -145,7 +145,7 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | | `MIN_ACTIVATION_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | *[New in Electra:EIP7251]* Minimum balance for a validator to become active | -| `MAX_EFFECTIVE_BALANCE_ELECTRA` | `Gwei(2**11 * 10**9)` (= 2048,000,000,000) | *[New in Electra:EIP7251]* Maximum balance for a compounding validator | +| `MAX_EFFECTIVE_BALANCE_ELECTRA` | `Gwei(2**11 * 10**9)` (= 2048,000,000,000) | *[New in Electra:EIP7251]* Maximum effective balance for a compounding validator | ### Rewards and penalties From c66245228483e096470fc7fb158248ffec05b3f3 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 7 Nov 2024 11:15:38 -0600 Subject: [PATCH 039/141] Move SingleAttestation after ExecutionRequests --- specs/electra/beacon-chain.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 290694087d..d9e6affc9a 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -271,16 +271,6 @@ class ConsolidationRequest(Container): target_pubkey: BLSPubkey ``` -#### `SingleAttestation` - -```python -class SingleAttestation(Container): - committee_index: CommitteeIndex - attester_index: ValidatorIndex - data: AttestationData - signature: BLSSignature -``` - #### `ExecutionRequests` *Note*: This container holds requests from the execution layer that are received in [ @@ -294,6 +284,16 @@ class ExecutionRequests(Container): consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] ``` +#### `SingleAttestation` + +```python +class SingleAttestation(Container): + committee_index: CommitteeIndex + attester_index: ValidatorIndex + data: AttestationData + signature: BLSSignature +``` + ### Modified Containers #### `AttesterSlashing` From 62e6a30ec1237db3f3d9d294a409d88cdc1fe1d8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 13 Nov 2024 13:42:15 +0700 Subject: [PATCH 040/141] Add `BLOB_SIDECAR_SUBNET_COUNT_EIP7594`, `MAX_BLOBS_PER_BLOCK_EIP7594`, and `MAX_REQUEST_BLOB_SIDECARS_EIP7594` --- configs/mainnet.yaml | 4 + configs/minimal.yaml | 4 + specs/_features/eip7594/beacon-chain.md | 141 +++++++++++++++++++++++ specs/_features/eip7594/p2p-interface.md | 84 ++++++++++++++ specs/deneb/beacon-chain.md | 2 +- 5 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 specs/_features/eip7594/beacon-chain.md diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 56c20a439c..36b4db4123 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -165,6 +165,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 +BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8 +MAX_BLOBS_PER_BLOCK_EIP7594: 8 +# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` +MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 # [New in Electra:EIP7251] MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 # 2**7 * 10**9 (= 128,000,000,000) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index a2b4f2e736..ae19518af7 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -164,6 +164,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 +BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8 +MAX_BLOBS_PER_BLOCK_EIP7594: 8 +# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` +MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 # [New in Electra:EIP7251] MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 # 2**6 * 10**9 (= 64,000,000,000) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md new file mode 100644 index 0000000000..bf980b840d --- /dev/null +++ b/specs/_features/eip7594/beacon-chain.md @@ -0,0 +1,141 @@ +# EIP7594 -- The Beacon Chain + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Configuration](#configuration) + - [Execution](#execution) + - [Execution payload](#execution-payload) + - [Modified `process_execution_payload`](#modified-process_execution_payload) +- [Testing](#testing) + + + + +## Introduction + +*Note:* This specification is built upon [Electra](../electra/beacon-chain.md) and is under active development. + +## Configuration + +### Execution + +| Name | Value | Description | +| - | - | - | +| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7494]* maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | + + +#### Execution payload + +##### Modified `process_execution_payload` + +```python +def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: + payload = body.execution_payload + + # Verify consistency of the parent hash with respect to the previous execution payload header + assert payload.parent_hash == state.latest_execution_payload_header.block_hash + # Verify prev_randao + assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state)) + # Verify timestamp + assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) + # Verify commitments are under limit + assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594 # [Modified in EIP7594] + # Verify the execution payload is valid + versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] + assert execution_engine.verify_and_notify_new_payload( + NewPayloadRequest( + execution_payload=payload, + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + execution_requests=body.execution_requests, + ) + ) + # Cache execution payload header + state.latest_execution_payload_header = ExecutionPayloadHeader( + parent_hash=payload.parent_hash, + fee_recipient=payload.fee_recipient, + state_root=payload.state_root, + receipts_root=payload.receipts_root, + logs_bloom=payload.logs_bloom, + prev_randao=payload.prev_randao, + block_number=payload.block_number, + gas_limit=payload.gas_limit, + gas_used=payload.gas_used, + timestamp=payload.timestamp, + extra_data=payload.extra_data, + base_fee_per_gas=payload.base_fee_per_gas, + block_hash=payload.block_hash, + transactions_root=hash_tree_root(payload.transactions), + withdrawals_root=hash_tree_root(payload.withdrawals), + blob_gas_used=payload.blob_gas_used, + excess_blob_gas=payload.excess_blob_gas, + ) +``` + +## Testing + +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7594 testing only. + +```python +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, + eth1_timestamp: uint64, + deposits: Sequence[Deposit], + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() + ) -> BeaconState: + fork = Fork( + previous_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] for testing only + current_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] + epoch=GENESIS_EPOCH, + ) + state = BeaconState( + genesis_time=eth1_timestamp + GENESIS_DELAY, + fork=fork, + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy + deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX, + ) + + # Process deposits + leaves = list(map(lambda deposit: deposit.data, deposits)) + for index, deposit in enumerate(deposits): + deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) + state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) + process_deposit(state, deposit) + + # Process deposit balance updates + validator_pubkeys = [v.pubkey for v in state.validators] + for deposit in state.pending_deposits: + validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey)) + increase_balance(state, validator_index, deposit.amount) + state.pending_deposits = [] + + # Process activations + for index, validator in enumerate(state.validators): + balance = state.balances[index] + validator.effective_balance = min( + balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator)) + if validator.effective_balance >= MIN_ACTIVATION_BALANCE: + validator.activation_eligibility_epoch = GENESIS_EPOCH + validator.activation_epoch = GENESIS_EPOCH + + # Set genesis validators root for domain separation and chain versioning + state.genesis_validators_root = hash_tree_root(state.validators) + + # Fill in sync committees + # Note: A duplicate committee is assigned for the current and next committee at genesis + state.current_sync_committee = get_next_sync_committee(state) + state.next_sync_committee = get_next_sync_committee(state) + + # Initialize the execution payload header + state.latest_execution_payload_header = execution_payload_header + + return state +``` diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index c989711807..8fa1d2b82f 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -21,11 +21,15 @@ - [MetaData](#metadata) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) - [Blob subnets](#blob-subnets) - [Deprecated `blob_sidecar_{subnet_id}`](#deprecated-blob_sidecar_subnet_id) - [`data_column_sidecar_{subnet_id}`](#data_column_sidecar_subnet_id) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) + - [BlobSidecarsByRoot v2](#blobsidecarsbyroot-v2) + - [BlobSidecarsByRange v2](#blobsidecarsbyrange-v2) - [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1) - [DataColumnSidecarsByRange v1](#datacolumnsidecarsbyrange-v1) - [GetMetaData v3](#getmetadata-v3) @@ -52,6 +56,8 @@ |------------------------------------------------|------------------------------------------------|---------------------------------------------------------------------------| | `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | | `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | +| `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request | +| `BLOB_SIDECAR_SUBNET_COUNT_EIP7594` | `2**3` (= 8) | The number of blob sidecar subnets used in the gossipsub protocol. | ### Containers @@ -154,6 +160,16 @@ Some gossip meshes are upgraded in the EIP-7594 fork to support upgraded types. #### Topics and messages + +##### Global topics + +###### `beacon_block` + +*Updated validation* + +- _[REJECT]_ The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- + i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594` + ##### Blob subnets ###### Deprecated `blob_sidecar_{subnet_id}` @@ -189,6 +205,74 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi #### Messages +##### BlobSidecarsByRoot v2 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` + +*[Updated in EIP7594]* + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | + +Request Content: + +``` +( + List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_EIP7594] +) +``` + +Response Content: + +``` +( + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594] +) +``` + +*Updated validation* + +No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. + + +##### BlobSidecarsByRange v2 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` + +*[Updated in EIP7594]* + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | + +Request Content: +``` +( + start_slot: Slot + count: uint64 +) +``` + +Response Content: +``` +( + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594] +) +``` + +*Updated validation* + +Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` sidecars. + ##### DataColumnSidecarsByRoot v1 **Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_root/1/` diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 0f6a8fc076..3404b11713 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -77,7 +77,7 @@ Deneb is a consensus-layer upgrade containing a number of features. Including: | Name | Value | Description | | - | - | - | -| `MAX_BLOB_COMMITMENTS_PER_BLOCK` | `uint64(2**12)` (= 4096) | *[New in Deneb:EIP4844]* hardfork independent fixed theoretical limit same as `LIMIT_BLOBS_PER_TX` (see EIP 4844) | +| `MAX_BLOB_COMMITMENTS_PER_BLOCK` | `uint64(2**12)` (= 4096) | *[New in Deneb:EIP4844]* hardfork independent fixed theoretical limit same as `TARGET_BLOB_GAS_PER_BLOCK` (see EIP 4844) | ## Configuration From f67e6cc359feb634b8a4d303891e774e15009e03 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 13 Nov 2024 14:23:23 +0700 Subject: [PATCH 041/141] update tests --- .../test_process_execution_payload.py | 3 ++- .../eth2spec/test/deneb/sanity/test_blocks.py | 11 ++++++----- .../eip7594/unittests/test_config_invariants.py | 13 +++++++++++++ tests/core/pyspec/eth2spec/test/helpers/blob.py | 11 +++++++++++ .../pyspec/eth2spec/test/helpers/fork_choice.py | 2 +- tests/core/pyspec/eth2spec/test/helpers/forks.py | 6 +++++- .../eth2spec/test/utils/randomized_block_tests.py | 1 + tests/formats/fork_choice/README.md | 2 +- 8 files changed, 40 insertions(+), 9 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py index d0c4a6f22a..e8ac314e10 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py @@ -12,6 +12,7 @@ ) from eth2spec.test.helpers.blob import ( get_sample_blob_tx, + get_max_blob_count, ) @@ -254,7 +255,7 @@ def test_invalid_correct_input__execution_invalid(spec, state): def test_invalid_exceed_max_blobs_per_block(spec, state): execution_payload = build_empty_execution_payload(spec, state) - opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=spec.config.MAX_BLOBS_PER_BLOCK + 1) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=get_max_blob_count(spec) + 1) execution_payload.transactions = [opaque_tx] execution_payload.block_hash = compute_el_block_hash(spec, execution_payload, state) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index b019175369..19c0fcd0c5 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -16,6 +16,7 @@ ) from eth2spec.test.helpers.blob import ( get_sample_blob_tx, + get_max_blob_count, ) @@ -72,31 +73,31 @@ def test_one_blob_two_txs(spec, state): @with_deneb_and_later @spec_state_test def test_one_blob_max_txs(spec, state): - yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=spec.MAX_BLOBS_PER_BLOCK) + yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=get_max_blob_count(spec)) @with_deneb_and_later @spec_state_test def test_invalid_one_blob_max_plus_one_txs(spec, state): - yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=spec.MAX_BLOBS_PER_BLOCK + 1, valid=False) + yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=get_max_blob_count(spec) + 1, valid=False) @with_deneb_and_later @spec_state_test def test_max_blobs_per_block(spec, state): - yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) + yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec)) @with_deneb_and_later @spec_state_test def test_invalid_max_blobs_per_block_two_txs(spec, state): - yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK, tx_count=2, valid=False) + yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec), tx_count=2, valid=False) @with_deneb_and_later @spec_state_test def test_invalid_exceed_max_blobs_per_block(spec, state): - yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK + 1, valid=False) + yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec) + 1, valid=False) @with_deneb_and_later diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py index fc54cc3088..2c291890d4 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py @@ -25,3 +25,16 @@ def test_invariants(spec): @single_phase def test_polynomical_commitments_sampling(spec): assert spec.FIELD_ELEMENTS_PER_EXT_BLOB == 2 * spec.FIELD_ELEMENTS_PER_BLOB + + +@with_eip7594_and_later +@spec_test +@single_phase +def test_networking(spec): + assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 < spec.MAX_BLOB_COMMITMENTS_PER_BLOCK + assert ( + spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 == + spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 + ) + # Start with the same size, but `BLOB_SIDECAR_SUBNET_COUNT` could potentially increase later. + assert spec.config.BLOB_SIDECAR_SUBNET_COUNT_EIP7594 == spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 diff --git a/tests/core/pyspec/eth2spec/test/helpers/blob.py b/tests/core/pyspec/eth2spec/test/helpers/blob.py index fb2354a501..a31f032dcd 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/blob.py +++ b/tests/core/pyspec/eth2spec/test/helpers/blob.py @@ -2,6 +2,10 @@ from rlp import encode, Serializable from rlp.sedes import Binary, CountableList, List as RLPList, big_endian_int, binary +from eth2spec.test.helpers.forks import ( + is_post_eip7594, +) + class Eip4844RlpTransaction(Serializable): fields = ( @@ -99,3 +103,10 @@ def get_sample_blob_tx(spec, blob_count=1, rng=random.Random(5566), is_valid_blo ) opaque_tx = bytes([0x03]) + encode(signed_blob_tx) return opaque_tx, blobs, blob_kzg_commitments, blob_kzg_proofs + + +def get_max_blob_count(spec): + if is_post_eip7594: + return spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 + else: + return spec.config.MAX_BLOBS_PER_BLOCK diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py index 8598870fb6..43555c268d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py @@ -178,7 +178,7 @@ def add_block(spec, # Check blob_data if blob_data is not None: - blobs = spec.List[spec.Blob, spec.config.MAX_BLOBS_PER_BLOCK](blob_data.blobs) + blobs = spec.List[spec.Blob, spec.config.MAX_BLOB_COMMITMENTS_PER_BLOCK](blob_data.blobs) blobs_root = blobs.hash_tree_root() yield get_blobs_file_name(blobs_root=blobs_root), blobs diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 288ad0d9e9..e261e3a754 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,6 +1,6 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - ELECTRA, WHISK, EIP7732, + ELECTRA, WHISK, EIP7732, EIP7594, PREVIOUS_FORK_OF, ) @@ -45,6 +45,10 @@ def is_post_whisk(spec): return is_post_fork(spec.fork, WHISK) +def is_post_eip7594(spec): + return is_post_fork(spec.fork, EIP7594) + + def is_post_eip7732(spec): return is_post_fork(spec.fork, EIP7732) diff --git a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py index 6e6cdd7683..93bb3b204c 100644 --- a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py @@ -250,6 +250,7 @@ def random_block_capella(spec, state, signed_blocks, scenario_state, rng=Random( def random_block_deneb(spec, state, signed_blocks, scenario_state, rng=Random(3456)): block = random_block_capella(spec, state, signed_blocks, scenario_state, rng=rng) # TODO: more commitments. blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] + # TODO: add MAX_BLOBS_PER_BLOCK_EIP7594 at fulu opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx( spec, blob_count=rng.randint(0, spec.config.MAX_BLOBS_PER_BLOCK), rng=rng) block.body.execution_payload.transactions.append(opaque_tx) diff --git a/tests/formats/fork_choice/README.md b/tests/formats/fork_choice/README.md index 1258a66c06..258dfe433d 100644 --- a/tests/formats/fork_choice/README.md +++ b/tests/formats/fork_choice/README.md @@ -86,7 +86,7 @@ The parameter that is required for executing `on_block(store, block)`. block: string -- the name of the `block_<32-byte-root>.ssz_snappy` file. To execute `on_block(store, block)` with the given attestation. blobs: string -- optional, the name of the `blobs_<32-byte-root>.ssz_snappy` file. - The blobs file content is a `List[Blob, MAX_BLOBS_PER_BLOCK]` SSZ object. + The blobs file content is a `List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK]` SSZ object. proofs: array of byte48 hex string -- optional, the proofs of blob commitments. valid: bool -- optional, default to `true`. If it's `false`, this execution step is expected to be invalid. From 34918e9744298a93153ecae6923fcb6cb8e109d3 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 18 Nov 2024 08:29:40 +0700 Subject: [PATCH 042/141] Remove unnecessary modification --- specs/electra/beacon-chain.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 861d8f0059..922294ce55 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -56,7 +56,6 @@ - [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit) - [New `get_consolidation_churn_limit`](#new-get_consolidation_churn_limit) - [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw) - - [Modified `get_indexed_attestation`](#modified-get_indexed_attestation) - [Modified `get_attesting_indices`](#modified-get_attesting_indices) - [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices) - [Beacon state mutators](#beacon-state-mutators) @@ -573,25 +572,6 @@ def get_pending_balance_to_withdraw(state: BeaconState, validator_index: Validat ) ``` -#### Modified `get_indexed_attestation` - -*Note*: The function is modified to use the new `get_attesting_indices`. - -```python -def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation: - """ - Return the indexed attestation corresponding to ``attestation``. - """ - # [Modified in Electra:EIP7549] - attesting_indices = get_attesting_indices(state, attestation) - - return IndexedAttestation( - attesting_indices=sorted(attesting_indices), - data=attestation.data, - signature=attestation.signature, - ) -``` - #### Modified `get_attesting_indices` *Note*: The function `get_attesting_indices` is modified to support EIP7549. @@ -1304,7 +1284,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: # Participation flag indices participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) - # Verify signature [Modified in Electra:EIP7549] + # Verify signature assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) # Update epoch participation flags @@ -1314,7 +1294,6 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: epoch_participation = state.previous_epoch_participation proposer_reward_numerator = 0 - # [Modified in Electra:EIP7549] for index in get_attesting_indices(state, attestation): for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): From ac53675d24915ffe1c4a81c8caf025d2dab5ed25 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 19 Nov 2024 14:26:08 -0600 Subject: [PATCH 043/141] Fix some minor nits --- specs/_features/eip7594/beacon-chain.md | 3 +- specs/_features/eip7594/p2p-interface.md | 30 ++++++++++--------- .../unittests/test_config_invariants.py | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index bf980b840d..28031178e1 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -28,8 +28,7 @@ | Name | Value | Description | | - | - | - | -| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7494]* maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | - +| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | #### Execution payload diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 8fa1d2b82f..de2d7e1f0b 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -52,12 +52,12 @@ *[New in EIP7594]* -| Name | Value | Description | -|------------------------------------------------|------------------------------------------------|---------------------------------------------------------------------------| -| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | -| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | -| `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request | -| `BLOB_SIDECAR_SUBNET_COUNT_EIP7594` | `2**3` (= 8) | The number of blob sidecar subnets used in the gossipsub protocol. | +| Name | Value | Description | +|------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------| +| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | +| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | +| `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request | +| `BLOB_SIDECAR_SUBNET_COUNT_EIP7594` | `2**3` (= 8) | The number of blob sidecar subnets used in the gossipsub protocol | ### Containers @@ -160,7 +160,6 @@ Some gossip meshes are upgraded in the EIP-7594 fork to support upgraded types. #### Topics and messages - ##### Global topics ###### `beacon_block` @@ -215,9 +214,9 @@ The `` field is calculated as `context = compute_fork_digest(fork [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------|-------------------------------| -| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|------------------------|-----------------------| +| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: @@ -239,7 +238,6 @@ Response Content: No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. - ##### BlobSidecarsByRange v2 **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` @@ -250,11 +248,12 @@ The `` field is calculated as `context = compute_fork_digest(fork [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------|-------------------------------| -| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|------------------------|-----------------------| +| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: + ``` ( start_slot: Slot @@ -263,6 +262,7 @@ Request Content: ``` Response Content: + ``` ( List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594] @@ -336,6 +336,7 @@ The `` field is calculated as `context = compute_fork_digest(fork | `EIP7594_FORK_VERSION` | `eip7594.DataColumnSidecar` | Request Content: + ``` ( start_slot: Slot @@ -345,6 +346,7 @@ Request Content: ``` Response Content: + ``` ( List[DataColumnSidecar, MAX_REQUEST_DATA_COLUMN_SIDECARS] diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py index 2c291890d4..8d14f4ae1c 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py @@ -31,7 +31,7 @@ def test_polynomical_commitments_sampling(spec): @spec_test @single_phase def test_networking(spec): - assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 < spec.MAX_BLOB_COMMITMENTS_PER_BLOCK + assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 == spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 From 7b0b7df0156edeb31b465a9a31fcfdbbc272c7b6 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 19 Nov 2024 14:33:16 -0600 Subject: [PATCH 044/141] Fix bug --- tests/core/pyspec/eth2spec/test/helpers/blob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/blob.py b/tests/core/pyspec/eth2spec/test/helpers/blob.py index a31f032dcd..c65414b02b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/blob.py +++ b/tests/core/pyspec/eth2spec/test/helpers/blob.py @@ -106,7 +106,7 @@ def get_sample_blob_tx(spec, blob_count=1, rng=random.Random(5566), is_valid_blo def get_max_blob_count(spec): - if is_post_eip7594: + if is_post_eip7594(spec): return spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 else: return spec.config.MAX_BLOBS_PER_BLOCK From 5753be7e78cfc2e62ea988e155c5a7c74258fde9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 19 Nov 2024 14:53:38 -0600 Subject: [PATCH 045/141] Fix blobs cast --- tests/core/pyspec/eth2spec/test/helpers/fork_choice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py index 43555c268d..33e8535502 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py @@ -178,7 +178,7 @@ def add_block(spec, # Check blob_data if blob_data is not None: - blobs = spec.List[spec.Blob, spec.config.MAX_BLOB_COMMITMENTS_PER_BLOCK](blob_data.blobs) + blobs = spec.List[spec.Blob, spec.MAX_BLOB_COMMITMENTS_PER_BLOCK](blob_data.blobs) blobs_root = blobs.hash_tree_root() yield get_blobs_file_name(blobs_root=blobs_root), blobs From e472afd14407169d685723706842130162277942 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 20 Nov 2024 10:32:35 -0600 Subject: [PATCH 046/141] Include requests_root in block_hash computation --- .../test/helpers/execution_payload.py | 42 +++++++++++++++---- .../pyspec/eth2spec/test/helpers/genesis.py | 5 +++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 0766008b84..fa24309320 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -1,4 +1,5 @@ from eth_hash.auto import keccak +from hashlib import sha256 from trie import HexaryTrie from rlp import encode from rlp.sedes import big_endian_int, Binary, List @@ -7,7 +8,12 @@ from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.debug.random_value import get_random_bytes_list from eth2spec.test.helpers.withdrawals import get_expected_withdrawals -from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb, is_post_eip7732 +from eth2spec.test.helpers.forks import ( + is_post_capella, + is_post_deneb, + is_post_electra, + is_post_eip7732, +) def get_execution_payload_header(spec, execution_payload): @@ -59,13 +65,22 @@ def compute_trie_root_from_indexed_data(data): return t.root_hash +def compute_requests_hash(block_requests): + m = sha256() + for r in block_requests: + if len(r) > 1: + m.update(sha256(r)) + return m.digest() + + # https://eips.ethereum.org/EIPS/eip-4895 # https://eips.ethereum.org/EIPS/eip-4844 def compute_el_header_block_hash(spec, payload_header, transactions_trie_root, withdrawals_trie_root=None, - parent_beacon_block_root=None): + parent_beacon_block_root=None, + requests_root=None): """ Computes the RLP execution block hash described by an `ExecutionPayloadHeader`. """ @@ -116,6 +131,9 @@ def compute_el_header_block_hash(spec, execution_payload_header_rlp.append((big_endian_int, payload_header.excess_blob_gas)) # parent_beacon_root execution_payload_header_rlp.append((Binary(32, 32), parent_beacon_block_root)) + if is_post_electra(spec): + # requests_root + execution_payload_header_rlp.append((Binary(32, 32), requests_root)) sedes = List([schema for schema, _ in execution_payload_header_rlp]) values = [value for _, value in execution_payload_header_rlp] @@ -191,7 +209,7 @@ def get_consolidation_request_rlp_bytes(consolidation_request): return b"\x02" + encode(values, sedes) -def compute_el_block_hash_with_parent_root(spec, payload, parent_beacon_block_root): +def compute_el_block_hash_with_new_fields(spec, payload, parent_beacon_block_root, requests_root): if payload == spec.ExecutionPayload(): return spec.Hash32() @@ -213,25 +231,35 @@ def compute_el_block_hash_with_parent_root(spec, payload, parent_beacon_block_ro transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, + requests_root, ) def compute_el_block_hash(spec, payload, pre_state): parent_beacon_block_root = None + requests_root = None if is_post_deneb(spec): previous_block_header = pre_state.latest_block_header.copy() if previous_block_header.state_root == spec.Root(): previous_block_header.state_root = pre_state.hash_tree_root() parent_beacon_block_root = previous_block_header.hash_tree_root() + if is_post_electra(spec): + requests_root = compute_requests_hash([]) - return compute_el_block_hash_with_parent_root( - spec, payload, parent_beacon_block_root) + return compute_el_block_hash_with_new_fields( + spec, payload, parent_beacon_block_root, requests_root) def compute_el_block_hash_for_block(spec, block): - return compute_el_block_hash_with_parent_root( - spec, block.body.execution_payload, block.parent_root) + requests_root = None + + if is_post_electra(spec): + requests_list = spec.get_execution_requests_list(block.body.execution_requests) + requests_root = compute_requests_hash(requests_list) + + return compute_el_block_hash_with_new_fields( + spec, block.body.execution_payload, block.parent_root, requests_root) def build_empty_post_eip7732_execution_payload_header(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index bd4e5d3bf3..3213169145 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -1,3 +1,4 @@ +from hashlib import sha256 from eth2spec.test.helpers.constants import ( PHASE0, PREVIOUS_FORK_OF, @@ -66,11 +67,14 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") withdrawals_trie_root = None parent_beacon_block_root = None + requests_root = None if is_post_capella(spec): withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") if is_post_deneb(spec): parent_beacon_block_root = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000") + if is_post_electra(spec): + requests_root = sha256(b"").digest() payload_header.block_hash = compute_el_header_block_hash( spec, @@ -78,6 +82,7 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, + requests_root, ) return payload_header From b1c9d279bda21400caa9897c6552b6aa9ea9cec2 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 20 Nov 2024 10:34:36 -0600 Subject: [PATCH 047/141] Add comment to compute_requests_hash --- tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index fa24309320..e38a4c5045 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -65,6 +65,7 @@ def compute_trie_root_from_indexed_data(data): return t.root_hash +# https://eips.ethereum.org/EIPS/eip-7685 def compute_requests_hash(block_requests): m = sha256() for r in block_requests: From de52c76bd38a954c58270d402214ac716a9474a3 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 21 Nov 2024 23:58:31 +0100 Subject: [PATCH 048/141] Fix block hash computation for deposit transition tests Request hash is not considered in `compute_el_block_hash`, have to use one of the other overloads for this to work. --- .../test/electra/sanity/blocks/test_deposit_transition.py | 6 +++--- .../core/pyspec/eth2spec/test/helpers/execution_payload.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py index 9749c89ffd..a9c2c62814 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py @@ -12,7 +12,7 @@ prepare_deposit_request, ) from eth2spec.test.helpers.execution_payload import ( - compute_el_block_hash, + compute_el_block_hash_for_block, ) from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.state import ( @@ -134,7 +134,7 @@ def prepare_state_and_block(spec, # Assign deposits and deposit requests block.body.deposits = deposits block.body.execution_requests.deposits = deposit_requests - block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) return state, block @@ -251,7 +251,7 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Artificially assign deposit's pubkey to a deposit request of the same block top_up_keys = [block.body.deposits[0].data.pubkey] block.body.execution_requests.deposits[0].pubkey = top_up_keys[0] - block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) pre_pending_deposits = len(state.pending_deposits) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index e38a4c5045..fe54b00b66 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -70,7 +70,7 @@ def compute_requests_hash(block_requests): m = sha256() for r in block_requests: if len(r) > 1: - m.update(sha256(r)) + m.update(sha256(r).digest()) return m.digest() From 266a64c3934b5ef8582e4b1cdcc2570b64dd1240 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Fri, 22 Nov 2024 09:27:55 +0700 Subject: [PATCH 049/141] remove `initialize_beacon_state_from_eth1` from post-altair forks --- .idea/.gitignore | 3 + .idea/consensus-specs.iml | 17 +++++ .../inspectionProfiles/profiles_settings.xml | 6 ++ .idea/misc.xml | 4 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 7 ++ docs/docs/templates/beacon-chain-template.md | 16 ----- specs/_features/eip7594/beacon-chain.md | 61 ----------------- specs/_features/whisk/beacon-chain.md | 22 ------ specs/altair/beacon-chain.md | 49 -------------- specs/capella/beacon-chain.md | 55 --------------- specs/deneb/beacon-chain.md | 56 ---------------- specs/electra/beacon-chain.md | 67 ------------------- 13 files changed, 45 insertions(+), 326 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/consensus-specs.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/consensus-specs.iml b/.idea/consensus-specs.iml new file mode 100644 index 0000000000..5195124935 --- /dev/null +++ b/.idea/consensus-specs.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000..105ce2da2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000..a48634ea73 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..4a1a1b45aa --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..6b11edb947 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/docs/templates/beacon-chain-template.md b/docs/docs/templates/beacon-chain-template.md index 4d22d3908e..02e95d4c4f 100644 --- a/docs/docs/templates/beacon-chain-template.md +++ b/docs/docs/templates/beacon-chain-template.md @@ -66,19 +66,3 @@ class CONTAINER_NAME(Container): ### Block processing - - - - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure testing only. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - ... -``` diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index 28031178e1..fd44068054 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -77,64 +77,3 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi excess_blob_gas=payload.excess_blob_gas, ) ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7594 testing only. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] for testing only - current_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX, - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process deposit balance updates - validator_pubkeys = [v.pubkey for v in state.validators] - for deposit in state.pending_deposits: - validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey)) - increase_balance(state, validator_index, deposit.amount) - state.pending_deposits = [] - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min( - balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator)) - if validator.effective_balance >= MIN_ACTIVATION_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # Initialize the execution payload header - state.latest_execution_payload_header = execution_payload_header - - return state -``` diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 9c2cb389a3..88428e05de 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -436,25 +436,3 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: assert state.latest_block_header.slot == state.slot # sanity check `process_block_header` has been called return state.latest_block_header.proposer_index ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified purely for Whisk testing. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - state_capella = capella.initialize_beacon_state_from_eth1( - eth1_block_hash, - eth1_timestamp, - deposits, - execution_payload_header, - ) - state = upgrade_to_whisk(state_capella) - state.fork.previous_version = WHISK_FORK_VERSION - state.fork.current_version = WHISK_FORK_VERSION - return state -``` diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 4bad3b556e..62609dcc39 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -672,52 +672,3 @@ def process_sync_committee_updates(state: BeaconState) -> None: state.current_sync_committee = state.next_sync_committee state.next_sync_committee = get_next_sync_committee(state) ``` - -## Initialize state for pure Altair testnets and test vectors - -This helper function is only for initializing the state for pure Altair testnets and tests. - -*Note*: The function `initialize_beacon_state_from_eth1` is modified: (1) using `ALTAIR_FORK_VERSION` as the previous and current fork version, (2) utilizing the Altair `BeaconBlockBody` when constructing the initial `latest_block_header`, and (3) adding initial sync committees. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit]) -> BeaconState: - fork = Fork( - previous_version=ALTAIR_FORK_VERSION, # [Modified in Altair] for testing only - current_version=ALTAIR_FORK_VERSION, # [Modified in Altair] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # [New in Altair] Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - return state -``` diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 103530bf8b..b0191364ee 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -484,58 +484,3 @@ def process_bls_to_execution_change(state: BeaconState, + address_change.to_execution_address ) ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Capella testing only. -Modifications include: -1. Use `CAPELLA_FORK_VERSION` as the previous and current fork version. -2. Utilize the Capella `BeaconBlockBody` when constructing the initial `latest_block_header`. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=CAPELLA_FORK_VERSION, # [Modified in Capella] for testing only - current_version=CAPELLA_FORK_VERSION, # [Modified in Capella] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # Initialize the execution payload header - state.latest_execution_payload_header = execution_payload_header - - return state -``` diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index e1ac44d66d..5eacc89b8c 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -466,59 +466,3 @@ def process_registry_updates(state: BeaconState) -> None: validator = state.validators[index] validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only. - -The `BeaconState` initialization is unchanged, except for the use of the updated `deneb.BeaconBlockBody` type -when initializing the first body-root. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=DENEB_FORK_VERSION, # [Modified in Deneb] for testing only - current_version=DENEB_FORK_VERSION, # [Modified in Deneb] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # Initialize the execution payload header - # If empty, will initialize a chain that has not yet gone through the Merge transition - state.latest_execution_payload_header = execution_payload_header - - return state -``` diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 0e51a6e3dc..915ee2b1c1 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1666,70 +1666,3 @@ def process_consolidation_request( if has_eth1_withdrawal_credential(target_validator): switch_to_compounding_validator(state, target_index) ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Electra testing only. -Modifications include: -1. Use `ELECTRA_FORK_VERSION` as the previous and current fork version. -2. Utilize the Electra `BeaconBlockBody` when constructing the initial `latest_block_header`. -3. *[New in Electra:EIP6110]* Add `deposit_requests_start_index` variable to the genesis state initialization. -4. *[New in Electra:EIP7251]* Initialize new fields to support increasing the maximum effective balance. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=ELECTRA_FORK_VERSION, # [Modified in Electra:EIP6110] for testing only - current_version=ELECTRA_FORK_VERSION, # [Modified in Electra:EIP6110] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX, # [New in Electra:EIP6110] - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process deposit balance updates - validator_pubkeys = [v.pubkey for v in state.validators] - for deposit in state.pending_deposits: - validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey)) - increase_balance(state, validator_index, deposit.amount) - state.pending_deposits = [] - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - # [Modified in Electra:EIP7251] - validator.effective_balance = min( - balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator)) - if validator.effective_balance >= MIN_ACTIVATION_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # Initialize the execution payload header - state.latest_execution_payload_header = execution_payload_header - - return state -``` From 15e3f151d7c7951a489404e20540b2049286d545 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 22 Nov 2024 09:03:02 +0100 Subject: [PATCH 050/141] Fix block hash computation for withdrawal sanity tests Request hash is not considered in `compute_el_block_hash`, have to use one of the other overloads for this to work. --- .../eth2spec/test/electra/sanity/blocks/test_blocks.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py index c3d2284610..5a4b98c3c8 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py @@ -9,7 +9,7 @@ get_signed_address_change, ) from eth2spec.test.helpers.execution_payload import ( - compute_el_block_hash, + compute_el_block_hash_for_block, ) from eth2spec.test.helpers.voluntary_exits import ( prepare_signed_exits, @@ -42,7 +42,7 @@ def test_basic_el_withdrawal_request(spec, state): ) block = build_empty_block_for_next_slot(spec, state) block.body.execution_requests.withdrawals = [withdrawal_request] - block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] @@ -80,7 +80,7 @@ def test_basic_btec_and_el_withdrawal_request_in_same_block(spec, state): ) block.body.execution_requests.withdrawals = [withdrawal_request] - block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] @@ -132,7 +132,7 @@ def test_basic_btec_before_el_withdrawal_request(spec, state): ) block_2 = build_empty_block_for_next_slot(spec, state) block_2.body.execution_requests.withdrawals = [withdrawal_request] - block_2.body.execution_payload.block_hash = compute_el_block_hash(spec, block_2.body.execution_payload, state) + block_2.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block_2) signed_block_2 = state_transition_and_sign_block(spec, state, block_2) yield 'blocks', [signed_block_1, signed_block_2] @@ -165,7 +165,7 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state): block = build_empty_block_for_next_slot(spec, state) block.body.voluntary_exits = signed_voluntary_exits block.body.execution_requests.withdrawals = [withdrawal_request] - block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] From 6e9526360ad34c44f699b511e60fec61f323cb7c Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 22 Nov 2024 13:31:41 +0100 Subject: [PATCH 051/141] Clean up dead link and typo in LC docs for Electra Followup from #3987 to remove references to the deleted document. --- specs/electra/light-client/fork.md | 2 +- specs/electra/light-client/sync-protocol.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/electra/light-client/fork.md b/specs/electra/light-client/fork.md index a315146b0e..902c1d6bf3 100644 --- a/specs/electra/light-client/fork.md +++ b/specs/electra/light-client/fork.md @@ -33,7 +33,7 @@ def normalize_merkle_branch(branch: Sequence[Bytes32], ## Upgrading light client data -A Electra `LightClientStore` can still process earlier light client data. In order to do so, that pre-Electra data needs to be locally upgraded to Electra before processing. +An Electra `LightClientStore` can still process earlier light client data. In order to do so, that pre-Electra data needs to be locally upgraded to Electra before processing. ```python def upgrade_lc_header_to_electra(pre: deneb.LightClientHeader) -> LightClientHeader: diff --git a/specs/electra/light-client/sync-protocol.md b/specs/electra/light-client/sync-protocol.md index f042119b00..e3e41cfb79 100644 --- a/specs/electra/light-client/sync-protocol.md +++ b/specs/electra/light-client/sync-protocol.md @@ -27,7 +27,6 @@ This upgrade updates light client data to include the Electra changes to the [`ExecutionPayload`](../beacon-chain.md) structure and to the generalized indices of surrounding containers. It extends the [Deneb Light Client specifications](../../deneb/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Deneb based deployments to Electra. Additional documents describes the impact of the upgrade on certain roles: -- [Full node](./full-node.md) - [Networking](./p2p-interface.md) ## Custom types From 4aad8ebcdc1cb8030e1f6b2a8d05a8adfb6b45ef Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 22 Nov 2024 07:02:29 -0600 Subject: [PATCH 052/141] Rename requests_root to requests_hash --- .../test/helpers/execution_payload.py | 22 +++++++++---------- .../pyspec/eth2spec/test/helpers/genesis.py | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index fe54b00b66..80684b9e6e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -81,7 +81,7 @@ def compute_el_header_block_hash(spec, transactions_trie_root, withdrawals_trie_root=None, parent_beacon_block_root=None, - requests_root=None): + requests_hash=None): """ Computes the RLP execution block hash described by an `ExecutionPayloadHeader`. """ @@ -133,8 +133,8 @@ def compute_el_header_block_hash(spec, # parent_beacon_root execution_payload_header_rlp.append((Binary(32, 32), parent_beacon_block_root)) if is_post_electra(spec): - # requests_root - execution_payload_header_rlp.append((Binary(32, 32), requests_root)) + # requests_hash + execution_payload_header_rlp.append((Binary(32, 32), requests_hash)) sedes = List([schema for schema, _ in execution_payload_header_rlp]) values = [value for _, value in execution_payload_header_rlp] @@ -210,7 +210,7 @@ def get_consolidation_request_rlp_bytes(consolidation_request): return b"\x02" + encode(values, sedes) -def compute_el_block_hash_with_new_fields(spec, payload, parent_beacon_block_root, requests_root): +def compute_el_block_hash_with_new_fields(spec, payload, parent_beacon_block_root, requests_hash): if payload == spec.ExecutionPayload(): return spec.Hash32() @@ -232,13 +232,13 @@ def compute_el_block_hash_with_new_fields(spec, payload, parent_beacon_block_roo transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, - requests_root, + requests_hash, ) def compute_el_block_hash(spec, payload, pre_state): parent_beacon_block_root = None - requests_root = None + requests_hash = None if is_post_deneb(spec): previous_block_header = pre_state.latest_block_header.copy() @@ -246,21 +246,21 @@ def compute_el_block_hash(spec, payload, pre_state): previous_block_header.state_root = pre_state.hash_tree_root() parent_beacon_block_root = previous_block_header.hash_tree_root() if is_post_electra(spec): - requests_root = compute_requests_hash([]) + requests_hash = compute_requests_hash([]) return compute_el_block_hash_with_new_fields( - spec, payload, parent_beacon_block_root, requests_root) + spec, payload, parent_beacon_block_root, requests_hash) def compute_el_block_hash_for_block(spec, block): - requests_root = None + requests_hash = None if is_post_electra(spec): requests_list = spec.get_execution_requests_list(block.body.execution_requests) - requests_root = compute_requests_hash(requests_list) + requests_hash = compute_requests_hash(requests_list) return compute_el_block_hash_with_new_fields( - spec, block.body.execution_payload, block.parent_root, requests_root) + spec, block.body.execution_payload, block.parent_root, requests_hash) def build_empty_post_eip7732_execution_payload_header(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 3213169145..9c43676a41 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -67,14 +67,14 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") withdrawals_trie_root = None parent_beacon_block_root = None - requests_root = None + requests_hash = None if is_post_capella(spec): withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") if is_post_deneb(spec): parent_beacon_block_root = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000") if is_post_electra(spec): - requests_root = sha256(b"").digest() + requests_hash = sha256(b"").digest() payload_header.block_hash = compute_el_header_block_hash( spec, @@ -82,7 +82,7 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, - requests_root, + requests_hash, ) return payload_header From db8f8529e21dbbdfe39e5f904d9addae24f55603 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 22 Nov 2024 15:18:21 +0100 Subject: [PATCH 053/141] Trim whitespace --- specs/deneb/p2p-interface.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index b13f62be55..52494accc2 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -194,9 +194,9 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: [0]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------------|-------------------------------| -| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|--------------------------------|---------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | ##### Attestation subnets @@ -318,9 +318,9 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: [0]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------------|-------------------------------| -| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|--------------------------------|---------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | ###### Blob retrieval via local execution layer client @@ -409,9 +409,9 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: [0]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|--------------------------------|-------------------------------| -| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|--------------------------------|---------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | ## Design decision rationale From d029ed309255b58446e8ec9aa369e1eab027cb4c Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Mon, 25 Nov 2024 15:30:14 +0700 Subject: [PATCH 054/141] remove `initialize_beacon_state_from_eth1` from bellatrix --- specs/_features/eip7594/beacon-chain.md | 1 - specs/_features/whisk/beacon-chain.md | 1 - specs/altair/beacon-chain.md | 1 - specs/bellatrix/beacon-chain.md | 60 ------------------- specs/capella/beacon-chain.md | 1 - specs/deneb/beacon-chain.md | 1 - specs/electra/beacon-chain.md | 1 - .../bellatrix/genesis/test_initialization.py | 20 ++----- 8 files changed, 6 insertions(+), 80 deletions(-) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index fd44068054..7ba88aa882 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -13,7 +13,6 @@ - [Execution](#execution) - [Execution payload](#execution-payload) - [Modified `process_execution_payload`](#modified-process_execution_payload) -- [Testing](#testing) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 88428e05de..1b62b28b4d 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -25,7 +25,6 @@ - [`BeaconBlockBody`](#beaconblockbody) - [Deposits](#deposits) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) -- [Testing](#testing) diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 62609dcc39..0b7e47a8be 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -54,7 +54,6 @@ - [Slashings](#slashings) - [Participation flags updates](#participation-flags-updates) - [Sync committee updates](#sync-committee-updates) -- [Initialize state for pure Altair testnets and test vectors](#initialize-state-for-pure-altair-testnets-and-test-vectors) diff --git a/specs/bellatrix/beacon-chain.md b/specs/bellatrix/beacon-chain.md index 51d570fe2d..3a6c6a4b86 100644 --- a/specs/bellatrix/beacon-chain.md +++ b/specs/bellatrix/beacon-chain.md @@ -44,7 +44,6 @@ - [`process_execution_payload`](#process_execution_payload) - [Epoch processing](#epoch-processing) - [Slashings](#slashings) -- [Testing](#testing) @@ -441,62 +440,3 @@ def process_slashings(state: BeaconState) -> None: penalty = penalty_numerator // total_balance * increment decrease_balance(state, ValidatorIndex(index), penalty) ``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Bellatrix testing only. -Modifications include: -1. Use `BELLATRIX_FORK_VERSION` as the previous and current fork version. -2. Utilize the Bellatrix `BeaconBlockBody` when constructing the initial `latest_block_header`. -3. Initialize `latest_execution_payload_header`. - If `execution_payload_header == ExecutionPayloadHeader()`, then the Merge has not yet occurred. - Else, the Merge starts from genesis and the transition is incomplete. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=BELLATRIX_FORK_VERSION, # [Modified in Bellatrix] for testing only - current_version=BELLATRIX_FORK_VERSION, # [Modified in Bellatrix] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # [New in Bellatrix] Initialize the execution payload header - # If empty, will initialize a chain that has not yet gone through the Merge transition - state.latest_execution_payload_header = execution_payload_header - - return state -``` diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index b0191364ee..54ac8a6782 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -38,7 +38,6 @@ - [Modified `process_execution_payload`](#modified-process_execution_payload) - [Modified `process_operations`](#modified-process_operations) - [New `process_bls_to_execution_change`](#new-process_bls_to_execution_change) -- [Testing](#testing) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 5eacc89b8c..43360f8b3e 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -42,7 +42,6 @@ - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) - [Epoch processing](#epoch-processing) - [Registry updates](#registry-updates) -- [Testing](#testing) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 915ee2b1c1..88731e6f17 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -106,7 +106,6 @@ - [Execution layer consolidation requests](#execution-layer-consolidation-requests) - [New `is_valid_switch_to_compounding_request`](#new-is_valid_switch_to_compounding_request) - [New `process_consolidation_request`](#new-process_consolidation_request) -- [Testing](#testing) diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py index 140d8708ca..6b456c1183 100644 --- a/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py @@ -14,7 +14,6 @@ get_sample_genesis_execution_payload_header, ) - def eth1_init_data(eth1_block_hash, eth1_timestamp): yield 'eth1', { 'eth1_block_hash': '0x' + eth1_block_hash.hex(), @@ -71,14 +70,10 @@ def test_initialize_pre_transition_empty_payload(spec): # initialize beacon_state *with* an *empty* execution_payload_header yield 'execution_payload_header', 'meta', True + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + state = spec.upgrade_to_bellatrix(state) execution_payload_header = spec.ExecutionPayloadHeader() - state = spec.initialize_beacon_state_from_eth1( - eth1_block_hash, - eth1_timestamp, - deposits, - execution_payload_header=execution_payload_header, - ) - + assert not spec.is_merge_transition_complete(state) yield 'execution_payload_header', execution_payload_header @@ -107,13 +102,10 @@ def test_initialize_post_transition(spec): # initialize beacon_state *with* an execution_payload_header yield 'execution_payload_header', 'meta', True + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + state = spec.upgrade_to_bellatrix(state) genesis_execution_payload_header = get_sample_genesis_execution_payload_header(spec) - state = spec.initialize_beacon_state_from_eth1( - eth1_block_hash, - eth1_timestamp, - deposits, - execution_payload_header=genesis_execution_payload_header, - ) + state.latest_execution_payload_header=genesis_execution_payload_header yield 'execution_payload_header', genesis_execution_payload_header From 8299014f0b89e559d0e8d3d5202dfc5940eb84ca Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 25 Nov 2024 16:49:01 +0600 Subject: [PATCH 055/141] Do no creds change on consolidation --- presets/mainnet/electra.yaml | 4 ++-- presets/minimal/electra.yaml | 4 ++-- specs/electra/beacon-chain.md | 10 +++------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/presets/mainnet/electra.yaml b/presets/mainnet/electra.yaml index a1a3501277..42afbb233e 100644 --- a/presets/mainnet/electra.yaml +++ b/presets/mainnet/electra.yaml @@ -29,8 +29,8 @@ WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096 MAX_ATTESTER_SLASHINGS_ELECTRA: 1 # `uint64(2**3)` (= 8) MAX_ATTESTATIONS_ELECTRA: 8 -# `uint64(2**0)` (= 1) -MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1 +# `uint64(2**1)` (= 2) +MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2 # Execution # --------------------------------------------------------------- diff --git a/presets/minimal/electra.yaml b/presets/minimal/electra.yaml index 1656491655..44e4769756 100644 --- a/presets/minimal/electra.yaml +++ b/presets/minimal/electra.yaml @@ -29,8 +29,8 @@ WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096 MAX_ATTESTER_SLASHINGS_ELECTRA: 1 # `uint64(2**3)` (= 8) MAX_ATTESTATIONS_ELECTRA: 8 -# `uint64(2**0)` (= 1) -MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1 +# `uint64(2**1)` (= 2) +MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2 # Execution # --------------------------------------------------------------- diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 6e7b536fbc..41164e33a8 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -184,7 +184,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | - | | `MAX_DEPOSIT_REQUESTS_PER_PAYLOAD` | `uint64(2**13)` (= 8,192) | *[New in Electra:EIP6110]* Maximum number of deposit receipts allowed in each payload | | `MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD` | `uint64(2**4)` (= 16)| *[New in Electra:EIP7002]* Maximum number of execution layer withdrawal requests in each payload | -| `MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD` | `uint64(1)` (= 1) | *[New in Electra:EIP7251]* Maximum number of execution layer consolidation requests in each payload | +| `MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD` | `uint64(2**1)` (= 2) | *[New in Electra:EIP7251]* Maximum number of execution layer consolidation requests in each payload | ### Withdrawals processing @@ -1643,8 +1643,8 @@ def process_consolidation_request( if not (has_correct_credential and is_correct_source_address): return - # Verify that target has execution withdrawal credentials - if not has_execution_withdrawal_credential(target_validator): + # Verify that target has compounding withdrawal credentials + if not has_compounding_withdrawal_credential(target_validator): return # Verify the source and the target are active @@ -1676,10 +1676,6 @@ def process_consolidation_request( source_index=source_index, target_index=target_index )) - - # Churn any target excess active balance of target and raise its max - if has_eth1_withdrawal_credential(target_validator): - switch_to_compounding_validator(state, target_index) ``` ## Testing From 3096a16354ea92ba85788ede145a32286cd57536 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 26 Nov 2024 12:57:34 +0100 Subject: [PATCH 056/141] Fix block hash computation for fork transition tests When overriding `execution_requests`, have to sync EL payload block hash as the requests are linked to it. Note that this was only caught now because the new request tests were added after the latest fixes applied. --- .../pyspec/eth2spec/test/helpers/fork_transition.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 69e1be669b..fa900a656b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -23,11 +23,15 @@ prepare_state_and_deposit, prepare_deposit_request, ) +from eth2spec.test.helpers.execution_payload import ( + compute_el_block_hash_for_block, +) from eth2spec.test.helpers.proposer_slashings import ( get_valid_proposer_slashing, ) from eth2spec.test.helpers.forks import ( get_next_fork_transition, + is_post_bellatrix, is_post_electra, ) from eth2spec.test.helpers.state import ( @@ -57,13 +61,15 @@ class OperationType(Enum): CONSOLIDATION_REQUEST = auto() -def _set_operations_by_dict(block, operation_dict): +def _set_operations_by_dict(spec, block, operation_dict): for key, value in operation_dict.items(): # to handle e.g. `execution_requests.deposits` and `deposits` obj = block.body for attr in key.split('.')[:-1]: obj = getattr(obj, attr) setattr(obj, key.split('.')[-1], value) + if is_post_bellatrix(spec): + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) def _state_transition_and_sign_block_at_slot(spec, @@ -87,7 +93,7 @@ def _state_transition_and_sign_block_at_slot(spec, block.body.sync_aggregate = sync_aggregate if operation_dict: - _set_operations_by_dict(block, operation_dict) + _set_operations_by_dict(spec, block, operation_dict) assert state.latest_block_header.slot < block.slot assert state.slot == block.slot @@ -403,7 +409,7 @@ def _check_state(): if is_right_before_fork: # add a block with operation. block = build_empty_block_for_next_slot(spec, state) - _set_operations_by_dict(block, operation_dict) + _set_operations_by_dict(spec, block, operation_dict) signed_block = state_transition_and_sign_block(spec, state, block) blocks.append(pre_tag(signed_block)) From 654333ea105e9abbbdd757cd875ea28516c9800a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 27 Nov 2024 00:17:42 +0800 Subject: [PATCH 057/141] Add EIP-7691 --- configs/mainnet.yaml | 22 ++-- configs/minimal.yaml | 20 +++- specs/_features/eip7594/p2p-interface.md | 12 +- specs/electra/beacon-chain.md | 10 +- specs/electra/p2p-interface.md | 111 ++++++++++++++++-- .../unittests/test_config_invariants.py | 13 ++ .../core/pyspec/eth2spec/test/helpers/blob.py | 3 + 7 files changed, 163 insertions(+), 28 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 36b4db4123..3a6873a678 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -144,14 +144,26 @@ ATTESTATION_SUBNET_PREFIX_BITS: 6 # Deneb # `2**7` (=128) MAX_REQUEST_BLOCKS_DENEB: 128 -# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK -MAX_REQUEST_BLOB_SIDECARS: 768 # `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096 # `6` BLOB_SIDECAR_SUBNET_COUNT: 6 -## `uint64(6)` +# `uint64(6)` MAX_BLOBS_PER_BLOCK: 6 +# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK +MAX_REQUEST_BLOB_SIDECARS: 768 + +# Electra +# 2**7 * 10**9 (= 128,000,000,000) +MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 +# 2**8 * 10**9 (= 256,000,000,000) +MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 +# `9` +BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 +# `uint64(9)` +MAX_BLOBS_PER_BLOCK_ELECTRA: 9 +# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA +MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 # Whisk # `Epoch(2**8)` @@ -170,9 +182,5 @@ MAX_BLOBS_PER_BLOCK_EIP7594: 8 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 -# [New in Electra:EIP7251] -MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 # 2**7 * 10**9 (= 128,000,000,000) -MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 # 2**8 * 10**9 (= 256,000,000,000) - # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index ae19518af7..6560304ff7 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -145,14 +145,26 @@ ATTESTATION_SUBNET_PREFIX_BITS: 6 # Deneb # `2**7` (=128) MAX_REQUEST_BLOCKS_DENEB: 128 -# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK -MAX_REQUEST_BLOB_SIDECARS: 768 # `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096 # `6` BLOB_SIDECAR_SUBNET_COUNT: 6 ## `uint64(6)` MAX_BLOBS_PER_BLOCK: 6 +# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK +MAX_REQUEST_BLOB_SIDECARS: 768 + +# Electra +# [customized] 2**6 * 10**9 (= 64,000,000,000) +MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 +# [customized] 2**7 * 10**9 (= 128,000,000,000) +MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 +# `9` +BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 +# `uint64(9)` +MAX_BLOBS_PER_BLOCK_ELECTRA: 9 +# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA +MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 # Whisk WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 @@ -169,9 +181,5 @@ MAX_BLOBS_PER_BLOCK_EIP7594: 8 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 -# [New in Electra:EIP7251] -MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 # 2**6 * 10**9 (= 64,000,000,000) -MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 # 2**7 * 10**9 (= 128,000,000,000) - # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index de2d7e1f0b..c1cc467332 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -28,8 +28,8 @@ - [`data_column_sidecar_{subnet_id}`](#data_column_sidecar_subnet_id) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) - - [BlobSidecarsByRoot v2](#blobsidecarsbyroot-v2) - - [BlobSidecarsByRange v2](#blobsidecarsbyrange-v2) + - [BlobSidecarsByRoot v3](#blobsidecarsbyroot-v3) + - [BlobSidecarsByRange v3](#blobsidecarsbyrange-v3) - [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1) - [DataColumnSidecarsByRange v1](#datacolumnsidecarsbyrange-v1) - [GetMetaData v3](#getmetadata-v3) @@ -204,9 +204,9 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi #### Messages -##### BlobSidecarsByRoot v2 +##### BlobSidecarsByRoot v3 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/3/` *[Updated in EIP7594]* @@ -238,9 +238,9 @@ Response Content: No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. -##### BlobSidecarsByRange v2 +##### BlobSidecarsByRange v3 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/3/` *[Updated in EIP7594]* diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 6e7b536fbc..c0dd098031 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -22,6 +22,7 @@ - [Withdrawals processing](#withdrawals-processing) - [Pending deposits processing](#pending-deposits-processing) - [Configuration](#configuration) + - [Execution](#execution-1) - [Validator cycle](#validator-cycle) - [Containers](#containers) - [New containers](#new-containers) @@ -119,6 +120,7 @@ Electra is a consensus-layer upgrade containing a number of features. Including: * [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002): Execution layer triggerable exits * [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Increase the MAX_EFFECTIVE_BALANCE * [EIP-7549](https://eips.ethereum.org/EIPS/eip-7549): Move committee index outside Attestation +* [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691): Blob throughput increase *Note:* This specification is built upon [Deneb](../deneb/beacon-chain.md) and is under active development. @@ -200,6 +202,12 @@ The following values are (non-configurable) constants used throughout the specif ## Configuration +### Execution + +| Name | Value | Description | +| - | - | - | +| `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP-7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | + ### Validator cycle | Name | Value | @@ -1205,7 +1213,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify commitments are under limit - assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK + assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_ELECTRA # [Modified in Electra:EIP7691] # Verify the execution payload is valid versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index 0ea33df9f7..d923e3f67e 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -11,18 +11,33 @@ The specification of these changes continues in the same format as the network s - [Modifications in Electra](#modifications-in-electra) + - [Configuration](#configuration) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) - - [Global topics](#global-topics) - - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) - - [Attestation subnets](#attestation-subnets) - - [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) + - [Attestation subnets](#attestation-subnets) + - [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BlobSidecarsByRoot v2](#blobsidecarsbyroot-v2) + - [BlobSidecarsByRange v2](#blobsidecarsbyrange-v2) ## Modifications in Electra +### Configuration + +*[New in Electra:EIP7691]* + +| Name | Value | Description | +|------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------| +| `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA` | Maximum number of blob sidecars in a single request | +| `BLOB_SIDECAR_SUBNET_COUNT_ELECTRA` | `9` | The number of blob sidecar subnets used in the gossipsub protocol | + ### The gossip domain: gossipsub Some gossip meshes are upgraded in the fork of Electra to support upgraded types. @@ -41,9 +56,16 @@ The specification around the creation, validation, and dissemination of messages The derivation of the `message-id` remains stable. -#### Global topics +##### Global topics + +###### `beacon_block` -##### `beacon_aggregate_and_proof` +*Updated validation* + +- _[REJECT]_ The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- + i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_ELECTRA` + +###### `beacon_aggregate_and_proof` The following convenience variables are re-defined - `index = get_committee_indices(aggregate.committee_bits)[0]` @@ -52,9 +74,9 @@ The following validations are added: * [REJECT] `len(committee_indices) == 1`, where `committee_indices = get_committee_indices(aggregate)`. * [REJECT] `aggregate.data.index == 0` -#### Attestation subnets +##### Attestation subnets -##### `beacon_attestation_{subnet_id}` +###### `beacon_attestation_{subnet_id}` The topic is updated to propagate `SingleAttestation` objects. @@ -71,3 +93,76 @@ The following validations are removed: that is, it has exactly one participating validator (`len([bit for bit in aggregation_bits if bit]) == 1`, i.e. exactly 1 bit is set). - _[REJECT]_ The number of aggregation bits matches the committee size -- i.e. `len(aggregation_bits) == len(get_beacon_committee(state, attestation.data.slot, index))`. + +### The Req/Resp domain + +#### Messages + +##### BlobSidecarsByRoot v2 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` + +*[Updated in ]* + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|------------------------|-----------------------| +| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | + +Request Content: + +``` +( + List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_ELECTRA] +) +``` + +Response Content: + +``` +( + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_ELECTRA] +) +``` + +*Updated validation* + +No more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` may be requested at a time. + +##### BlobSidecarsByRange v2 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` + +*[Updated in ]* + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|------------------------|-----------------------| +| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | + +Request Content: + +``` +( + start_slot: Slot + count: uint64 +) +``` + +Response Content: + +``` +( + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_ELECTRA] +) +``` + +*Updated validation* + +Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` sidecars. diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py index 839fa0dbd4..ce4b6684a4 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py @@ -13,3 +13,16 @@ def test_processing_pending_partial_withdrawals(spec): spec.MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP < spec.MAX_WITHDRAWALS_PER_PAYLOAD ) + + +@with_electra_and_later +@spec_test +@single_phase +def test_networking(spec): + assert spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK + assert ( + spec.config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA == + spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA + ) + # Start with the same size, but `BLOB_SIDECAR_SUBNET_COUNT` could potentially increase later. + assert spec.config.BLOB_SIDECAR_SUBNET_COUNT_ELECTRA == spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA diff --git a/tests/core/pyspec/eth2spec/test/helpers/blob.py b/tests/core/pyspec/eth2spec/test/helpers/blob.py index c65414b02b..e0d82da1a0 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/blob.py +++ b/tests/core/pyspec/eth2spec/test/helpers/blob.py @@ -3,6 +3,7 @@ from rlp.sedes import Binary, CountableList, List as RLPList, big_endian_int, binary from eth2spec.test.helpers.forks import ( + is_post_electra, is_post_eip7594, ) @@ -108,5 +109,7 @@ def get_sample_blob_tx(spec, blob_count=1, rng=random.Random(5566), is_valid_blo def get_max_blob_count(spec): if is_post_eip7594(spec): return spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 + elif is_post_electra(spec): + return spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA else: return spec.config.MAX_BLOBS_PER_BLOCK From 78c6922cafbe947220ee2cae07b4b8a706968a66 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 27 Nov 2024 00:58:29 +0800 Subject: [PATCH 058/141] bump minimal preset `MAX_BLOB_COMMITMENTS_PER_BLOCK` and `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` --- presets/minimal/deneb.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/presets/minimal/deneb.yaml b/presets/minimal/deneb.yaml index 9d0db086b8..c101de3162 100644 --- a/presets/minimal/deneb.yaml +++ b/presets/minimal/deneb.yaml @@ -5,6 +5,6 @@ # `uint64(4096)` FIELD_ELEMENTS_PER_BLOB: 4096 # [customized] -MAX_BLOB_COMMITMENTS_PER_BLOCK: 16 -# [customized] `floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 4 = 9 -KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9 +MAX_BLOB_COMMITMENTS_PER_BLOCK: 32 +# [customized] `floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 5 = 10 +KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 10 From 99f82e76b426b4973196de0706d6559359e1d75f Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Wed, 27 Nov 2024 13:03:06 +0600 Subject: [PATCH 059/141] Add pending deposit and consolidation tests --- .../test/electra/sanity/test_slots.py | 125 ++++++++++++++++++ tests/generators/sanity/main.py | 1 + 2 files changed, 126 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py new file mode 100644 index 0000000000..89f88ee4b3 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py @@ -0,0 +1,125 @@ +from eth2spec.test.context import ( + spec_state_test, + with_electra_and_later, +) +from eth2spec.test.helpers.deposits import prepare_pending_deposit +from eth2spec.test.helpers.state import transition_to + + +def run_epoch_processing(spec, state, pending_deposits=[], pending_consolidations=[]): + # Transition to the last slot of the epoch + slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) - 1 + transition_to(spec, state, slot) + state.pending_deposits = pending_deposits + state.pending_consolidations = pending_consolidations + yield 'pre', state + yield 'slots', 1 + spec.process_slots(state, state.slot + 1) + yield 'post', state + + assert state.pending_deposits == [] + assert state.pending_consolidations == [] + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey(spec, state): + # Create multiple deposits with the same pubkey + index = len(state.validators) + deposit = prepare_pending_deposit(spec, validator_index=index, amount=spec.MIN_ACTIVATION_BALANCE, signed=True) + pending_deposits = [deposit, deposit] + + yield from run_epoch_processing(spec, state, pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == spec.MIN_ACTIVATION_BALANCE + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_compounding(spec, state): + # Create multiple deposits with the same pubkey and compounding creds + index = len(state.validators) + deposit = prepare_pending_deposit( + spec, validator_index=index, amount=spec.MIN_ACTIVATION_BALANCE, signed=True, + withdrawal_credentials=(spec.COMPOUNDING_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x11' * 20) + ) + pending_deposits = [deposit, deposit] + + yield from run_epoch_processing(spec, state, pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == state.balances[index] + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_below_upward_threshold(spec, state): + # Create multiple deposits with top up lower than the upward threshold + index = len(state.validators) + deposit_0 = prepare_pending_deposit( + spec, validator_index=index, + amount=(spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT), signed=True + ) + deposit_1 = prepare_pending_deposit( + spec, validator_index=index, + amount=spec.EFFECTIVE_BALANCE_INCREMENT, signed=True + ) + pending_deposits = [deposit_0, deposit_1] + + yield from run_epoch_processing(spec, state, pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == deposit_0.amount + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_above_upward_threshold(spec, state): + # Create multiple deposits with top up greater than the upward threshold + index = len(state.validators) + deposit_0 = prepare_pending_deposit( + spec, validator_index=index, + amount=(spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT), signed=True + ) + amount = spec.EFFECTIVE_BALANCE_INCREMENT // spec.HYSTERESIS_QUOTIENT * spec.HYSTERESIS_UPWARD_MULTIPLIER + 1 + deposit_1 = prepare_pending_deposit(spec, validator_index=index, amount=amount, signed=True) + pending_deposits = [deposit_0, deposit_1] + + yield from run_epoch_processing(spec, state, pending_deposits) + + # Check deposit balance is applied correctly + balance = state.balances[index] + assert balance == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation(spec, state): + # Create pending consolidation + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set the source withdrawal credential to eth1 + state.validators[target_index].withdrawal_credentials = ( + spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + # Set the target withdrawal credential to compounding + state.validators[target_index].withdrawal_credentials = ( + spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + pending_consolidations = [spec.PendingConsolidation(source_index=source_index, target_index=target_index)] + + yield from run_epoch_processing(spec, state, pending_consolidations=pending_consolidations) + + # Check the consolidation is processed correctly + assert state.balances[source_index] == 0 + assert state.validators[source_index].effective_balance == 0 + assert state.balances[target_index] == spec.MIN_ACTIVATION_BALANCE * 2 + assert state.validators[target_index].effective_balance == spec.MIN_ACTIVATION_BALANCE * 2 diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 8039b82a44..2145146856 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -33,6 +33,7 @@ # do not forget to update sanity/block/__init__.py accordingly. _new_electra_mods = {key: 'eth2spec.test.electra.sanity.' + key for key in [ 'blocks', + 'slots', ]} electra_mods = combine_mods(_new_electra_mods, deneb_mods) From 518cb513fad3793fc994fad90a9e306ac2c63655 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Wed, 27 Nov 2024 17:57:33 +0700 Subject: [PATCH 060/141] delete .idea files --- .idea/.gitignore | 3 --- .idea/consensus-specs.iml | 17 ----------------- .idea/inspectionProfiles/profiles_settings.xml | 6 ------ .idea/misc.xml | 4 ---- .idea/modules.xml | 8 -------- .idea/vcs.xml | 7 ------- 6 files changed, 45 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/consensus-specs.iml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521af..0000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/consensus-specs.iml b/.idea/consensus-specs.iml deleted file mode 100644 index 5195124935..0000000000 --- a/.idea/consensus-specs.iml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da2d..0000000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index a48634ea73..0000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 4a1a1b45aa..0000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 6b11edb947..0000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file From 3beca1731cd179762d8ccf0eb60cd5c2a74faa46 Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Wed, 27 Nov 2024 23:38:09 +0700 Subject: [PATCH 061/141] EIP-7594: Remove BLOB_SIDECAR_SUBNET_COUNT_EIP7594 --- configs/mainnet.yaml | 1 - configs/minimal.yaml | 1 - specs/_features/eip7594/p2p-interface.md | 1 - .../eth2spec/test/eip7594/unittests/test_config_invariants.py | 2 -- 4 files changed, 5 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 36b4db4123..c80716009a 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -165,7 +165,6 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8 MAX_BLOBS_PER_BLOCK_EIP7594: 8 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index ae19518af7..61f4afb0dc 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -164,7 +164,6 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8 MAX_BLOBS_PER_BLOCK_EIP7594: 8 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index de2d7e1f0b..ad08cf69ff 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -57,7 +57,6 @@ | `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | | `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | | `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request | -| `BLOB_SIDECAR_SUBNET_COUNT_EIP7594` | `2**3` (= 8) | The number of blob sidecar subnets used in the gossipsub protocol | ### Containers diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py index 8d14f4ae1c..33eaada407 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py @@ -36,5 +36,3 @@ def test_networking(spec): spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 == spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 ) - # Start with the same size, but `BLOB_SIDECAR_SUBNET_COUNT` could potentially increase later. - assert spec.config.BLOB_SIDECAR_SUBNET_COUNT_EIP7594 == spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 From d2072df41df48fc4b010e5275f3c2191946f814d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 28 Nov 2024 23:54:28 +0800 Subject: [PATCH 062/141] minor suggestions --- .../eth2spec/test/electra/sanity/test_slots.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py index 89f88ee4b3..9ea506392b 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py @@ -6,7 +6,11 @@ from eth2spec.test.helpers.state import transition_to -def run_epoch_processing(spec, state, pending_deposits=[], pending_consolidations=[]): +def run_epoch_processing(spec, state, pending_deposits=None, pending_consolidations=None): + if pending_deposits is None: + pending_deposits = [] + if pending_consolidations is None: + pending_consolidations = [] # Transition to the last slot of the epoch slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) - 1 transition_to(spec, state, slot) @@ -29,7 +33,7 @@ def test_multiple_pending_deposits_same_pubkey(spec, state): deposit = prepare_pending_deposit(spec, validator_index=index, amount=spec.MIN_ACTIVATION_BALANCE, signed=True) pending_deposits = [deposit, deposit] - yield from run_epoch_processing(spec, state, pending_deposits) + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) # Check deposit balance is applied correctly assert state.balances[index] == sum(d.amount for d in pending_deposits) @@ -47,7 +51,7 @@ def test_multiple_pending_deposits_same_pubkey_compounding(spec, state): ) pending_deposits = [deposit, deposit] - yield from run_epoch_processing(spec, state, pending_deposits) + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) # Check deposit balance is applied correctly assert state.balances[index] == sum(d.amount for d in pending_deposits) @@ -69,7 +73,7 @@ def test_multiple_pending_deposits_same_pubkey_below_upward_threshold(spec, stat ) pending_deposits = [deposit_0, deposit_1] - yield from run_epoch_processing(spec, state, pending_deposits) + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) # Check deposit balance is applied correctly assert state.balances[index] == sum(d.amount for d in pending_deposits) @@ -116,6 +120,11 @@ def test_pending_consolidation(spec, state): ) pending_consolidations = [spec.PendingConsolidation(source_index=source_index, target_index=target_index)] + assert state.balances[source_index] == spec.MIN_ACTIVATION_BALANCE + assert state.validators[source_index].effective_balance == spec.MIN_ACTIVATION_BALANCE + assert state.balances[target_index] == spec.MIN_ACTIVATION_BALANCE + assert state.validators[target_index].effective_balance == spec.MIN_ACTIVATION_BALANCE + yield from run_epoch_processing(spec, state, pending_consolidations=pending_consolidations) # Check the consolidation is processed correctly From 53e8d6657859f2b6166819cb42c6c86560ad23a8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 28 Nov 2024 23:56:00 +0800 Subject: [PATCH 063/141] Add the missing `deneb.BlobSidecar` Co-authored-by: Pop Chunhapanya --- specs/electra/p2p-interface.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index d923e3f67e..0738a8a41d 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -110,6 +110,7 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | | `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | Request Content: @@ -144,6 +145,7 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | | `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | Request Content: From e7620583cfc3b63c66dd6f37f12105880d9b84b4 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Fri, 29 Nov 2024 00:42:11 +0700 Subject: [PATCH 064/141] delete bellatrix test_initialization.py, update with_phases --- .../test/bellatrix/genesis/__init__.py | 0 .../bellatrix/genesis/test_initialization.py | 114 ------------------ .../phase0/genesis/test_initialization.py | 13 +- 3 files changed, 7 insertions(+), 120 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/test/bellatrix/genesis/__init__.py delete mode 100644 tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/genesis/__init__.py b/tests/core/pyspec/eth2spec/test/bellatrix/genesis/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py deleted file mode 100644 index 6b456c1183..0000000000 --- a/tests/core/pyspec/eth2spec/test/bellatrix/genesis/test_initialization.py +++ /dev/null @@ -1,114 +0,0 @@ -from eth2spec.test.context import ( - BELLATRIX, - single_phase, - spec_test, - with_presets, - with_phases, - with_bellatrix_and_later, -) -from eth2spec.test.helpers.constants import MINIMAL -from eth2spec.test.helpers.deposits import ( - prepare_full_genesis_deposits, -) -from eth2spec.test.helpers.genesis import ( - get_sample_genesis_execution_payload_header, -) - -def eth1_init_data(eth1_block_hash, eth1_timestamp): - yield 'eth1', { - 'eth1_block_hash': '0x' + eth1_block_hash.hex(), - 'eth1_timestamp': int(eth1_timestamp), - } - - -@with_phases([BELLATRIX]) -@spec_test -@single_phase -@with_presets([MINIMAL], reason="too slow") -def test_initialize_pre_transition_no_param(spec): - deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, deposit_root, _ = prepare_full_genesis_deposits( - spec, - spec.MAX_EFFECTIVE_BALANCE, - deposit_count, - signed=True, - ) - - eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.config.MIN_GENESIS_TIME - - yield from eth1_init_data(eth1_block_hash, eth1_timestamp) - yield 'deposits', deposits - - # initialize beacon_state *without* an execution_payload_header - yield 'execution_payload_header', 'meta', False - state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) - - assert not spec.is_merge_transition_complete(state) - - yield 'state', state - - -@with_bellatrix_and_later -@spec_test -@single_phase -@with_presets([MINIMAL], reason="too slow") -def test_initialize_pre_transition_empty_payload(spec): - deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, deposit_root, _ = prepare_full_genesis_deposits( - spec, - spec.MAX_EFFECTIVE_BALANCE, - deposit_count, - signed=True, - ) - - eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.config.MIN_GENESIS_TIME - - yield from eth1_init_data(eth1_block_hash, eth1_timestamp) - yield 'deposits', deposits - - # initialize beacon_state *with* an *empty* execution_payload_header - yield 'execution_payload_header', 'meta', True - state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) - state = spec.upgrade_to_bellatrix(state) - execution_payload_header = spec.ExecutionPayloadHeader() - - assert not spec.is_merge_transition_complete(state) - - yield 'execution_payload_header', execution_payload_header - - yield 'state', state - - -@with_bellatrix_and_later -@spec_test -@single_phase -@with_presets([MINIMAL], reason="too slow") -def test_initialize_post_transition(spec): - deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, deposit_root, _ = prepare_full_genesis_deposits( - spec, - spec.MAX_EFFECTIVE_BALANCE, - deposit_count, - signed=True, - ) - - eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.config.MIN_GENESIS_TIME - - yield from eth1_init_data(eth1_block_hash, eth1_timestamp) - yield 'deposits', deposits - - # initialize beacon_state *with* an execution_payload_header - yield 'execution_payload_header', 'meta', True - state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) - state = spec.upgrade_to_bellatrix(state) - genesis_execution_payload_header = get_sample_genesis_execution_payload_header(spec) - state.latest_execution_payload_header=genesis_execution_payload_header - - yield 'execution_payload_header', genesis_execution_payload_header - - assert spec.is_merge_transition_complete(state) - - yield 'state', state diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py index ed584ed612..2a09617302 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py @@ -1,8 +1,9 @@ from eth2spec.test.context import ( + PHASE0, single_phase, spec_test, with_presets, - with_all_phases, + with_phases, ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.deposits import ( @@ -26,7 +27,7 @@ def eth1_init_data(eth1_block_hash, eth1_timestamp): } -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -62,7 +63,7 @@ def test_initialize_beacon_state_from_eth1(spec): yield 'state', state -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -113,7 +114,7 @@ def test_initialize_beacon_state_some_small_balances(spec): yield 'state', state -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -162,7 +163,7 @@ def test_initialize_beacon_state_one_topup_activation(spec): yield 'state', state -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -189,7 +190,7 @@ def test_initialize_beacon_state_random_invalid_genesis(spec): yield 'state', state -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") From 29d9e8dabe7199b11bf2c9eb99ec4e37aad3320a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 29 Nov 2024 04:04:11 +0800 Subject: [PATCH 065/141] Fix test cases source path --- tests/generators/sanity/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 2145146856..2101894d9c 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -31,10 +31,13 @@ # This is a "hack" which allows other test files (e.g., test_deposit_transition.py) # to reuse the sanity/block test format. If a new test file is added or removed, # do not forget to update sanity/block/__init__.py accordingly. - _new_electra_mods = {key: 'eth2spec.test.electra.sanity.' + key for key in [ + _new_electra_mods_1 = {key: 'eth2spec.test.electra.sanity.' + key for key in [ 'blocks', + ]} + _new_electra_mods_2 = {key: 'eth2spec.test.electra.sanity.test_' + key for key in [ 'slots', ]} + _new_electra_mods = {**_new_electra_mods_1, **_new_electra_mods_2} electra_mods = combine_mods(_new_electra_mods, deneb_mods) all_mods = { From ea2e07e3084f04b9b6e09a4590c3703a76a84a65 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Fri, 29 Nov 2024 13:41:23 +0700 Subject: [PATCH 066/141] Correct with_phases in test_validity.py --- .../eth2spec/test/phase0/genesis/test_validity.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py index d245b8fcf4..3304deebd8 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py @@ -1,8 +1,9 @@ from eth2spec.test.context import ( + PHASE0, spec_test, single_phase, with_presets, - with_all_phases, + with_phases, ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.deposits import ( @@ -43,7 +44,7 @@ def run_is_valid_genesis_state(spec, state, valid=True): assert is_valid == valid -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -56,7 +57,7 @@ def test_full_genesis_deposits(spec): yield from run_is_valid_genesis_state(spec, state) -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -70,7 +71,7 @@ def test_invalid_invalid_timestamp(spec): yield from run_is_valid_genesis_state(spec, state, valid=False) -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -84,7 +85,7 @@ def test_extra_balance(spec): yield from run_is_valid_genesis_state(spec, state) -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -107,7 +108,7 @@ def test_one_more_validator(spec): yield from run_is_valid_genesis_state(spec, state) -@with_all_phases +@with_phases([PHASE0]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") From ac4e7131db563dc62d98ee5776bb3fa47f1d2b69 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 29 Nov 2024 14:11:16 +0600 Subject: [PATCH 067/141] Update tests --- .../test_process_consolidation_request.py | 186 +++++------------- 1 file changed, 53 insertions(+), 133 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py index 8fdbb8e2e5..8f3bc14c7a 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py @@ -47,8 +47,8 @@ def test_basic_consolidation_in_current_consolidation_epoch(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set earliest consolidation epoch to the expected exit epoch expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) @@ -96,59 +96,7 @@ def test_basic_consolidation_with_excess_target_balance(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - - # Set earliest consolidation epoch to the expected exit epoch - expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - state.earliest_consolidation_epoch = expected_exit_epoch - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - # Set the consolidation balance to consume equal to churn limit - state.consolidation_balance_to_consume = consolidation_churn_limit - - # Add excess balance - state.balances[target_index] = state.balances[target_index] + spec.EFFECTIVE_BALANCE_INCREMENT - - yield from run_consolidation_processing(spec, state, consolidation) - - # Check consolidation churn is decremented correctly - assert ( - state.consolidation_balance_to_consume - == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE - ) - # Check exit epoch - assert state.validators[source_index].exit_epoch == expected_exit_epoch - - -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_basic_consolidation_with_excess_target_balance_and_compounding_credentials(spec, state): - # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation - state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - current_epoch = spec.get_current_epoch(state) - source_index = spec.get_active_validator_indices(state, current_epoch)[0] - target_index = spec.get_active_validator_indices(state, current_epoch)[1] - - # Set source to eth1 credentials - source_address = b"\x22" * 20 - set_eth1_withdrawal_credential_with_balance( - spec, state, source_index, address=source_address - ) - # Make consolidation with source address - consolidation = spec.ConsolidationRequest( - source_address=source_address, - source_pubkey=state.validators[source_index].pubkey, - target_pubkey=state.validators[target_index].pubkey, - ) - - # Set target to eth1 credentials + # Set target to compounding credentials set_compounding_withdrawal_credential(spec, state, target_index) # Set earliest consolidation epoch to the expected exit epoch @@ -202,8 +150,8 @@ def test_basic_consolidation_in_new_consolidation_epoch(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) yield from run_consolidation_processing(spec, state, consolidation) @@ -247,8 +195,8 @@ def test_basic_consolidation_with_preexisting_churn(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set earliest consolidation epoch to the expected exit epoch expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) @@ -296,8 +244,8 @@ def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set earliest consolidation epoch to the first available epoch state.earliest_consolidation_epoch = spec.compute_activation_exit_epoch( @@ -321,53 +269,6 @@ def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state): assert state.validators[source_index].exit_epoch == expected_exit_epoch -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_basic_consolidation_with_compounding_credentials(spec, state): - # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation - state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - current_epoch = spec.get_current_epoch(state) - source_index = spec.get_active_validator_indices(state, current_epoch)[0] - target_index = spec.get_active_validator_indices(state, current_epoch)[1] - - # Set source to eth1 credentials - source_address = b"\x22" * 20 - set_compounding_withdrawal_credential( - spec, state, source_index, address=source_address - ) - # Make consolidation with source address - consolidation = spec.ConsolidationRequest( - source_address=source_address, - source_pubkey=state.validators[source_index].pubkey, - target_pubkey=state.validators[target_index].pubkey, - ) - - # Set target to compounding credentials - set_compounding_withdrawal_credential(spec, state, target_index) - - # Set the consolidation balance to consume equal to churn limit - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - state.consolidation_balance_to_consume = consolidation_churn_limit - - yield from run_consolidation_processing(spec, state, consolidation) - - expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - # Check consolidation churn is decremented correctly - assert ( - state.consolidation_balance_to_consume - == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE - ) - # Check exit epoch - assert state.validators[source_index].exit_epoch == expected_exit_epoch - - @with_electra_and_later @with_presets([MINIMAL], "need sufficient consolidation churn limit") @with_custom_state( @@ -396,8 +297,8 @@ def test_consolidation_churn_limit_balance(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set source effective balance to consolidation churn limit consolidation_churn_limit = spec.get_consolidation_churn_limit(state) @@ -446,8 +347,8 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set source effective balance to 2 * consolidation churn limit consolidation_churn_limit = spec.get_consolidation_churn_limit(state) @@ -495,8 +396,8 @@ def test_consolidation_balance_through_two_churn_epochs(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - # Set target to eth1 credentials - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) # Set source balance higher to 3 * consolidation churn limit consolidation_churn_limit = spec.get_consolidation_churn_limit(state) @@ -857,7 +758,7 @@ def test_incorrect_no_source_execution_withdrawal_credential(spec, state): ) @spec_test @single_phase -def test_incorrect_no_target_execution_withdrawal_credential(spec, state): +def test_incorrect_target_bls_credential(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # Set up a correct consolidation, but target does not have @@ -883,6 +784,39 @@ def test_incorrect_no_target_execution_withdrawal_credential(spec, state): ) +@with_electra_and_later +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase +def test_incorrect_target_with_eth1_credential(spec, state): + # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + # Set up an otherwise correct consolidation + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + source_address = b"\x22" * 20 + set_eth1_withdrawal_credential_with_balance( + spec, state, source_index, address=source_address + ) + consolidation = spec.ConsolidationRequest( + source_address=source_address, + source_pubkey=state.validators[source_index].pubkey, + target_pubkey=state.validators[target_index].pubkey, + ) + + # Set target to eth1 credentials + set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + + yield from run_consolidation_processing( + spec, state, consolidation, success=False + ) + + @with_electra_and_later @with_presets([MINIMAL], "need sufficient consolidation churn limit") @with_custom_state( @@ -1228,7 +1162,7 @@ def run_consolidation_processing(spec, state, consolidation, success=True): pre_exit_epoch_source = source_validator.exit_epoch pre_exit_epoch_target = target_validator.exit_epoch pre_pending_consolidations = state.pending_consolidations.copy() - pre_target_withdrawal_credentials = target_validator.withdrawal_credentials + pre_source_balance = state.balances[source_index] pre_target_balance = state.balances[target_index] else: pre_state = state.copy() @@ -1266,23 +1200,9 @@ def run_consolidation_processing(spec, state, consolidation, success=True): target_index=target_index, ) assert state.pending_consolidations == pre_pending_consolidations + [expected_new_pending_consolidation] - # Check excess balance is queued if the target switched to compounding - if pre_target_withdrawal_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX: - post_target_withdrawal_credentials = ( - spec.COMPOUNDING_WITHDRAWAL_PREFIX + pre_target_withdrawal_credentials[1:] - ) - assert state.validators[target_index].withdrawal_credentials == post_target_withdrawal_credentials - assert state.balances[target_index] == spec.MIN_ACTIVATION_BALANCE - if pre_target_balance > spec.MIN_ACTIVATION_BALANCE: - assert len(state.pending_deposits) == 1 - pending_deposit = state.pending_deposits[0] - assert pending_deposit.pubkey == target_validator.pubkey - assert pending_deposit.withdrawal_credentials == post_target_withdrawal_credentials - assert pending_deposit.amount == (pre_target_balance - spec.MIN_ACTIVATION_BALANCE) - assert pending_deposit.signature == spec.G2_POINT_AT_INFINITY - assert pending_deposit.slot == spec.GENESIS_SLOT - else: - assert state.balances[target_index] == pre_target_balance + # Check no balance move happened + assert state.balances[source_index] == pre_source_balance + assert state.balances[target_index] == pre_target_balance else: assert pre_state == state From 86a7aec01b6b2c00d86736d82fadcdd9d43ff72d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 29 Nov 2024 19:14:37 +0800 Subject: [PATCH 068/141] Fix `test_incorrect_inactive_validator` by using correct `source_address` --- .../test_process_withdrawal_request.py | 176 +++++++++--------- 1 file changed, 87 insertions(+), 89 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py index 39626ee059..9b125afc17 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py @@ -13,6 +13,92 @@ set_eth1_withdrawal_credential_with_balance, set_compounding_withdrawal_credential, ) +# +# Run processing +# + + +def run_withdrawal_request_processing( + spec, state, withdrawal_request, valid=True, success=True +): + """ + Run ``process_withdrawal_request``, yielding: + - pre-state ('pre') + - withdrawal_request ('withdrawal_request') + - post-state ('post'). + If ``valid == False``, run expecting ``AssertionError`` + If ``success == False``, it doesn't initiate exit successfully + """ + yield "pre", state + yield "withdrawal_request", withdrawal_request + + if not valid: + expect_assertion_error( + lambda: spec.process_withdrawal_request( + state, withdrawal_request + ) + ) + yield "post", None + return + + pre_state = state.copy() + + spec.process_withdrawal_request( + state, withdrawal_request + ) + + yield "post", state + + if not success: + # No-op + assert pre_state == state + else: + validator_index = get_validator_index_by_pubkey( + state, withdrawal_request.validator_pubkey + ) + pre_exit_epoch = pre_state.validators[validator_index].exit_epoch + pre_pending_partial_withdrawals = pre_state.pending_partial_withdrawals.copy() + pre_balance = pre_state.balances[validator_index] + pre_effective_balance = pre_state.validators[validator_index].effective_balance + assert state.balances[validator_index] == pre_balance + assert ( + state.validators[validator_index].effective_balance == pre_effective_balance + ) + # Full exit request + if withdrawal_request.amount == spec.FULL_EXIT_REQUEST_AMOUNT: + assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + assert spec.get_pending_balance_to_withdraw(state, validator_index) == 0 + assert state.pending_partial_withdrawals == pre_pending_partial_withdrawals + # Partial withdrawal request + else: + expected_amount_to_withdraw = compute_amount_to_withdraw( + spec, pre_state, validator_index, withdrawal_request.amount + ) + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH + expected_withdrawable_epoch = ( + state.earliest_exit_epoch + + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + ) + expected_partial_withdrawal = spec.PendingPartialWithdrawal( + index=validator_index, + amount=expected_amount_to_withdraw, + withdrawable_epoch=expected_withdrawable_epoch, + ) + assert ( + state.pending_partial_withdrawals + == pre_pending_partial_withdrawals + [expected_partial_withdrawal] + ) + + +def compute_amount_to_withdraw(spec, state, index, amount): + pending_balance_to_withdraw = spec.get_pending_balance_to_withdraw(state, index) + return min( + state.balances[index] + - spec.MIN_ACTIVATION_BALANCE + - pending_balance_to_withdraw, + amount, + ) # Modified tests from 7002. Just testing EL-triggered exits, not partial withdrawals @@ -887,12 +973,11 @@ def test_incorrect_inactive_validator(spec, state): validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch)) validator_pubkey = state.validators[validator_index].pubkey address = b"\x22" * 20 - incorrect_address = b"\x33" * 20 set_eth1_withdrawal_credential_with_balance( spec, state, validator_index, address=address ) withdrawal_request = spec.WithdrawalRequest( - source_address=incorrect_address, + source_address=address, validator_pubkey=validator_pubkey, amount=spec.FULL_EXIT_REQUEST_AMOUNT, ) @@ -904,90 +989,3 @@ def test_incorrect_inactive_validator(spec, state): yield from run_withdrawal_request_processing( spec, state, withdrawal_request, success=False ) - -# -# Run processing -# - - -def run_withdrawal_request_processing( - spec, state, withdrawal_request, valid=True, success=True -): - """ - Run ``process_withdrawal_request``, yielding: - - pre-state ('pre') - - withdrawal_request ('withdrawal_request') - - post-state ('post'). - If ``valid == False``, run expecting ``AssertionError`` - If ``success == False``, it doesn't initiate exit successfully - """ - yield "pre", state - yield "withdrawal_request", withdrawal_request - - if not valid: - expect_assertion_error( - lambda: spec.process_withdrawal_request( - state, withdrawal_request - ) - ) - yield "post", None - return - - pre_state = state.copy() - - spec.process_withdrawal_request( - state, withdrawal_request - ) - - yield "post", state - - if not success: - # No-op - assert pre_state == state - else: - validator_index = get_validator_index_by_pubkey( - state, withdrawal_request.validator_pubkey - ) - pre_exit_epoch = pre_state.validators[validator_index].exit_epoch - pre_pending_partial_withdrawals = pre_state.pending_partial_withdrawals.copy() - pre_balance = pre_state.balances[validator_index] - pre_effective_balance = pre_state.validators[validator_index].effective_balance - assert state.balances[validator_index] == pre_balance - assert ( - state.validators[validator_index].effective_balance == pre_effective_balance - ) - # Full exit request - if withdrawal_request.amount == spec.FULL_EXIT_REQUEST_AMOUNT: - assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH - assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH - assert spec.get_pending_balance_to_withdraw(state, validator_index) == 0 - assert state.pending_partial_withdrawals == pre_pending_partial_withdrawals - # Partial withdrawal request - else: - expected_amount_to_withdraw = compute_amount_to_withdraw( - spec, pre_state, validator_index, withdrawal_request.amount - ) - assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH - expected_withdrawable_epoch = ( - state.earliest_exit_epoch - + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY - ) - expected_partial_withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, - amount=expected_amount_to_withdraw, - withdrawable_epoch=expected_withdrawable_epoch, - ) - assert ( - state.pending_partial_withdrawals - == pre_pending_partial_withdrawals + [expected_partial_withdrawal] - ) - - -def compute_amount_to_withdraw(spec, state, index, amount): - pending_balance_to_withdraw = spec.get_pending_balance_to_withdraw(state, index) - return min( - state.balances[index] - - spec.MIN_ACTIVATION_BALANCE - - pending_balance_to_withdraw, - amount, - ) From 4fc6ddecb28e57b537708958ea2be863881edcf9 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Fri, 29 Nov 2024 18:40:25 +0700 Subject: [PATCH 069/141] Add random execution requests --- .../eth2spec/test/helpers/multi_operations.py | 128 ++++++++++++++++-- .../test/utils/randomized_block_tests.py | 2 + 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 9943fcdd45..024b4dba9e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -18,6 +18,8 @@ from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change +from tests.core.pyspec.eth2spec.test.helpers.forks import is_post_electra + def run_slash_and_exit(spec, state, slash_index, exit_index, valid=True): """ @@ -129,15 +131,26 @@ def get_random_deposits(spec, state, rng, num_deposits=None): index = len(state.validators) + i withdrawal_pubkey = pubkeys[-1 - index] withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] - _, root, deposit_data_leaves = build_deposit( - spec, - deposit_data_leaves, - pubkeys[index], - privkeys[index], - spec.MAX_EFFECTIVE_BALANCE, - withdrawal_credentials=withdrawal_credentials, - signed=True, - ) + if is_post_electra(spec): + _, root, deposit_data_leaves = build_deposit( + spec, + deposit_data_leaves, + pubkeys[index], + privkeys[index], + spec.MAX_EFFECTIVE_BALANCE_ELECTRA, + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) + else: + _, root, deposit_data_leaves = build_deposit( + spec, + deposit_data_leaves, + pubkeys[index], + privkeys[index], + spec.MAX_EFFECTIVE_BALANCE, + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) # Then for that context, build deposits/proofs for i in range(num_deposits): @@ -257,3 +270,100 @@ def run_test_full_random_operations(spec, state, rng=Random(2080)): yield 'blocks', [signed_block] yield 'post', state + +def get_random_execution_requests(spec, state, rng=rng): + deposits = get_random_deposits_requests(spec, state, rng) + withdrawals = get_random_withdrawals_requests(spec, state, rng) + consolidations = get_random_consolidations_requests(spec, state, rng) + + execution_requests = spec.ExecutionRequests( + deposits=deposits, + withdrawals=withdrawals, + consolidations=consolidations + ) + + return execution_requests + +def get_random_deposits_requests(spec, state, rng=rng): + deposits, _ = get_random_deposits(spec, state, rng) + + deposits_requests = [] + + for deposit in deposits: + deposit_request = spec.DepositRequest( + pubkey=deposit.data.pubkey, + withdrawal_credentials=deposit.data.withdrawal_credentials, + amount=deposit.data.amount, + signature=deposit.data.signature, + index=deposit.data.index, + ) + deposits_requests.append(deposit_request) + + return deposits_requests + + +def get_random_withdrawals_requests(spec, state, rng, num_withdrawals=None): + if num_withdrawals is None: + num_withdrawals = rng.randint(0, spec.MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD) + + withdrawals_requests = [] + + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + + current_epoch = spec.get_current_epoch(state) + active_validator_indices = spec.get_active_validator_indices(state, current_epoch) + rng.shuffle(active_validator_indices) + + for _ in range(num_withdrawals): + if not active_validator_indices: + break + + address = rng.getrandbits(160).to_bytes(20, 'big') + + validator_index = active_validator_indices.pop() + validator = state.validators[validator_index] + + withdrawal_request = spec.WithdrawalRequest( + source_address=address, + validator_pubkey=validator.pubkey, + amount=spec.FULL_EXIT_REQUEST_AMOUNT, + ) + + withdrawals_requests.append(withdrawal_request) + + return withdrawals_requests + + +def get_random_consolidations_requests(spec, state, rng, num_consolidations=None): + if num_consolidations is None: + num_consolidations = rng.randint(0, spec.MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD) + + consolidations_requests = [] + + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + + current_epoch = spec.get_current_epoch(state) + active_validator_indices = spec.get_active_validator_indices(state, current_epoch) + rng.shuffle(active_validator_indices) + + for _ in range(num_consolidations): + if len(active_validator_indices) < 2: + break + + source_address = rng.getrandbits(160).to_bytes(20, 'big') + + source_index = active_validator_indices.pop() + target_index = active_validator_indices.pop() + + source_validator = state.validators[source_index] + target_validator = state.validators[target_index] + + consolidation_request = spec.ConsolidationRequest( + source_address=source_address, + source_pubkey=source_validator.pubkey, + target_pubkey=target_validator.pubkey, + ) + + consolidations_requests.append(consolidation_request) + + return consolidations_requests \ No newline at end of file diff --git a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py index 93bb3b204c..df67872880 100644 --- a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py @@ -16,6 +16,7 @@ get_random_bls_to_execution_changes, get_random_sync_aggregate, prepare_state_and_get_random_deposits, + get_random_execution_requests, ) from eth2spec.test.helpers.inactivity_scores import ( randomize_inactivity_scores, @@ -262,6 +263,7 @@ def random_block_deneb(spec, state, signed_blocks, scenario_state, rng=Random(34 def random_block_electra(spec, state, signed_blocks, scenario_state, rng=Random(3456)): block = random_block_deneb(spec, state, signed_blocks, scenario_state, rng=rng) + block.body.execution_requests = get_random_execution_requests(spec, state, rng=rng) return block From 966d59f8981de604996e05548a939a3d1a0dc31e Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Mon, 2 Dec 2024 07:58:52 -0600 Subject: [PATCH 070/141] Fix table of contents --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index d9e6affc9a..24fa2bb69f 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -30,8 +30,8 @@ - [`DepositRequest`](#depositrequest) - [`WithdrawalRequest`](#withdrawalrequest) - [`ConsolidationRequest`](#consolidationrequest) - - [`SingleAttestation`](#singleattestation) - [`ExecutionRequests`](#executionrequests) + - [`SingleAttestation`](#singleattestation) - [Modified Containers](#modified-containers) - [`AttesterSlashing`](#attesterslashing) - [`BeaconBlockBody`](#beaconblockbody) From 8ff2f4c9e2ed413d7c763fb862c7037dc73b9ae1 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Mon, 2 Dec 2024 21:34:57 +0700 Subject: [PATCH 071/141] Add random deposits requests --- .../eth2spec/test/helpers/multi_operations.py | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 024b4dba9e..845f83651c 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -18,8 +18,6 @@ from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change -from tests.core.pyspec.eth2spec.test.helpers.forks import is_post_electra - def run_slash_and_exit(spec, state, slash_index, exit_index, valid=True): """ @@ -131,26 +129,15 @@ def get_random_deposits(spec, state, rng, num_deposits=None): index = len(state.validators) + i withdrawal_pubkey = pubkeys[-1 - index] withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] - if is_post_electra(spec): - _, root, deposit_data_leaves = build_deposit( - spec, - deposit_data_leaves, - pubkeys[index], - privkeys[index], - spec.MAX_EFFECTIVE_BALANCE_ELECTRA, - withdrawal_credentials=withdrawal_credentials, - signed=True, - ) - else: - _, root, deposit_data_leaves = build_deposit( - spec, - deposit_data_leaves, - pubkeys[index], - privkeys[index], - spec.MAX_EFFECTIVE_BALANCE, - withdrawal_credentials=withdrawal_credentials, - signed=True, - ) + _, root, deposit_data_leaves = build_deposit( + spec, + deposit_data_leaves, + pubkeys[index], + privkeys[index], + spec.MAX_EFFECTIVE_BALANCE, + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) # Then for that context, build deposits/proofs for i in range(num_deposits): @@ -271,7 +258,7 @@ def run_test_full_random_operations(spec, state, rng=Random(2080)): yield 'blocks', [signed_block] yield 'post', state -def get_random_execution_requests(spec, state, rng=rng): +def get_random_execution_requests(spec, state, rng): deposits = get_random_deposits_requests(spec, state, rng) withdrawals = get_random_withdrawals_requests(spec, state, rng) consolidations = get_random_consolidations_requests(spec, state, rng) @@ -284,12 +271,29 @@ def get_random_execution_requests(spec, state, rng=rng): return execution_requests -def get_random_deposits_requests(spec, state, rng=rng): - deposits, _ = get_random_deposits(spec, state, rng) +def get_random_deposits_requests(spec, state, rng, num_deposits=None): + if num_deposits is None: + num_deposits = rng.randrange(0, spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD) + + deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))] deposits_requests = [] - for deposit in deposits: + for i in range(num_deposits): + index = rng.randrange(0, num_deposits) + withdrawal_pubkey = pubkeys[index] + withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] + + deposit, _, _ = build_deposit( + spec, + deposit_data_leaves, + pubkeys[index], + privkeys[index], + rng.randint(spec.MIN_ACTIVATION_BALANCE, spec.MAX_EFFECTIVE_BALANCE_ELECTRA), + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) + deposit_request = spec.DepositRequest( pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, @@ -312,7 +316,6 @@ def get_random_withdrawals_requests(spec, state, rng, num_withdrawals=None): current_epoch = spec.get_current_epoch(state) active_validator_indices = spec.get_active_validator_indices(state, current_epoch) - rng.shuffle(active_validator_indices) for _ in range(num_withdrawals): if not active_validator_indices: @@ -320,13 +323,14 @@ def get_random_withdrawals_requests(spec, state, rng, num_withdrawals=None): address = rng.getrandbits(160).to_bytes(20, 'big') - validator_index = active_validator_indices.pop() + validator_index = rng.choice(active_validator_indices) validator = state.validators[validator_index] + validator_balance = state.balances[validator_index] withdrawal_request = spec.WithdrawalRequest( source_address=address, validator_pubkey=validator.pubkey, - amount=spec.FULL_EXIT_REQUEST_AMOUNT, + amount=rng.randint(0, validator_balance), ) withdrawals_requests.append(withdrawal_request) @@ -344,16 +348,13 @@ def get_random_consolidations_requests(spec, state, rng, num_consolidations=None current_epoch = spec.get_current_epoch(state) active_validator_indices = spec.get_active_validator_indices(state, current_epoch) - rng.shuffle(active_validator_indices) for _ in range(num_consolidations): - if len(active_validator_indices) < 2: - break source_address = rng.getrandbits(160).to_bytes(20, 'big') - source_index = active_validator_indices.pop() - target_index = active_validator_indices.pop() + source_index = rng.choice(active_validator_indices) + target_index = rng.choice(active_validator_indices) source_validator = state.validators[source_index] target_validator = state.validators[target_index] From 333df69e65eaed1b7dac0fcde827123fb36c2401 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:28:37 -0600 Subject: [PATCH 072/141] Fix lint errors --- tests/core/pyspec/eth2spec/test/helpers/multi_operations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 845f83651c..83779a0257 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -271,6 +271,7 @@ def get_random_execution_requests(spec, state, rng): return execution_requests + def get_random_deposits_requests(spec, state, rng, num_deposits=None): if num_deposits is None: num_deposits = rng.randrange(0, spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD) @@ -367,4 +368,5 @@ def get_random_consolidations_requests(spec, state, rng, num_consolidations=None consolidations_requests.append(consolidation_request) - return consolidations_requests \ No newline at end of file + return consolidations_requests + From 120d7a4766b47e42131bba738037379dc2a9e2bd Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:29:11 -0600 Subject: [PATCH 073/141] Add another blank line --- tests/core/pyspec/eth2spec/test/helpers/multi_operations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 83779a0257..651c8b9285 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -258,6 +258,7 @@ def run_test_full_random_operations(spec, state, rng=Random(2080)): yield 'blocks', [signed_block] yield 'post', state + def get_random_execution_requests(spec, state, rng): deposits = get_random_deposits_requests(spec, state, rng) withdrawals = get_random_withdrawals_requests(spec, state, rng) From ab7cdb97e35faafa8bc495b7555c0941b62f48ff Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:13:26 -0600 Subject: [PATCH 074/141] Delete last line with trailing whitespace --- tests/core/pyspec/eth2spec/test/helpers/multi_operations.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 651c8b9285..9c0e50302f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -370,4 +370,3 @@ def get_random_consolidations_requests(spec, state, rng, num_consolidations=None consolidations_requests.append(consolidation_request) return consolidations_requests - From cd424814631a315954eb8b96fd9a66f25e128092 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Tue, 3 Dec 2024 13:07:26 +0600 Subject: [PATCH 075/141] Apply suggestions from @jtraglia Co-authored-by: Justin Traglia <95511699+jtraglia@users.noreply.github.com> --- .../block_processing/test_process_consolidation_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py index 8f3bc14c7a..59012217b5 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py @@ -758,7 +758,7 @@ def test_incorrect_no_source_execution_withdrawal_credential(spec, state): ) @spec_test @single_phase -def test_incorrect_target_bls_credential(spec, state): +def test_incorrect_target_with_bls_credential(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # Set up a correct consolidation, but target does not have From 35bbe4fb75e371c31799d4f3bb883de2d112b61b Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Tue, 3 Dec 2024 13:12:45 +0600 Subject: [PATCH 076/141] Bring back comp consolidation test --- .../test_process_consolidation_request.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py index 59012217b5..0d975e1d99 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py @@ -269,6 +269,53 @@ def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state): assert state.validators[source_index].exit_epoch == expected_exit_epoch +@with_electra_and_later +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase +def test_basic_consolidation_with_compounding_credentials(spec, state): + # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + + # Set source to compounding credentials + source_address = b"\x22" * 20 + set_compounding_withdrawal_credential( + spec, state, source_index, address=source_address + ) + # Make consolidation with source address + consolidation = spec.ConsolidationRequest( + source_address=source_address, + source_pubkey=state.validators[source_index].pubkey, + target_pubkey=state.validators[target_index].pubkey, + ) + + # Set target to compounding credentials + set_compounding_withdrawal_credential(spec, state, target_index) + + # Set the consolidation balance to consume equal to churn limit + consolidation_churn_limit = spec.get_consolidation_churn_limit(state) + state.consolidation_balance_to_consume = consolidation_churn_limit + + yield from run_consolidation_processing(spec, state, consolidation) + + expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) + # Check consolidation churn is decremented correctly + assert ( + state.consolidation_balance_to_consume + == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE + ) + # Check exit epoch + assert state.validators[source_index].exit_epoch == expected_exit_epoch + + @with_electra_and_later @with_presets([MINIMAL], "need sufficient consolidation churn limit") @with_custom_state( From 166d5f36d45a206aa5b69bc927a22203cc67cb11 Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Tue, 3 Dec 2024 16:36:06 +0700 Subject: [PATCH 077/141] Apply suggestions from code review Co-authored-by: Justin Traglia <95511699+jtraglia@users.noreply.github.com> --- tests/core/pyspec/eth2spec/test/helpers/multi_operations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 9c0e50302f..5c64d8cb43 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -291,7 +291,7 @@ def get_random_deposits_requests(spec, state, rng, num_deposits=None): deposit_data_leaves, pubkeys[index], privkeys[index], - rng.randint(spec.MIN_ACTIVATION_BALANCE, spec.MAX_EFFECTIVE_BALANCE_ELECTRA), + rng.randint(spec.EFFECTIVE_BALANCE_INCREMENT, 2 * spec.MAX_EFFECTIVE_BALANCE_ELECTRA), withdrawal_credentials=withdrawal_credentials, signed=True, ) @@ -303,6 +303,7 @@ def get_random_deposits_requests(spec, state, rng, num_deposits=None): signature=deposit.data.signature, index=deposit.data.index, ) + deposits_requests.append(deposit_request) return deposits_requests @@ -352,7 +353,6 @@ def get_random_consolidations_requests(spec, state, rng, num_consolidations=None active_validator_indices = spec.get_active_validator_indices(state, current_epoch) for _ in range(num_consolidations): - source_address = rng.getrandbits(160).to_bytes(20, 'big') source_index = rng.choice(active_validator_indices) From d66ef16472af77ee3c329634efc71bf8e5bfcdfd Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Tue, 3 Dec 2024 15:48:08 +0600 Subject: [PATCH 078/141] Limit consolidating balance by validator.effective_balance --- specs/electra/beacon-chain.md | 4 ++-- .../test_process_pending_consolidations.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 543782b71c..e39c4f79f9 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -957,8 +957,8 @@ def process_pending_consolidations(state: BeaconState) -> None: break # Calculate the consolidated balance - max_effective_balance = get_max_effective_balance(source_validator) - source_effective_balance = min(state.balances[pending_consolidation.source_index], max_effective_balance) + source_effective_balance = min( + state.balances[pending_consolidation.source_index], source_validator.effective_balance) # Move active balance to target. Excess balance is withdrawable. decrease_balance(state, pending_consolidation.source_index, source_effective_balance) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index b061efee7b..61b3e248aa 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -239,12 +239,12 @@ def test_pending_consolidation_compounding_creds(spec, state): # Pending consolidation was successfully processed expected_target_balance = ( - state_before_consolidation.balances[source_index] + state_before_consolidation.balances[target_index] + spec.MIN_ACTIVATION_BALANCE + state_before_consolidation.balances[target_index] ) assert state.balances[target_index] == expected_target_balance # All source balance is active and moved to the target, # because the source validator has compounding credentials - assert state.balances[source_index] == 0 + assert state.balances[source_index] == state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE assert state.pending_consolidations == [] # Pending balance deposit to the target is not created, @@ -297,10 +297,10 @@ def test_pending_consolidation_with_pending_deposit(spec, state): # Pending consolidation was successfully processed expected_target_balance = ( - state_before_consolidation.balances[source_index] + state_before_consolidation.balances[target_index] + spec.MIN_ACTIVATION_BALANCE + state_before_consolidation.balances[target_index] ) assert state.balances[target_index] == expected_target_balance - assert state.balances[source_index] == 0 + assert state.balances[source_index] == state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE assert state.pending_consolidations == [] # Pending deposit to the source was not processed. From 414987cb100c02baf0cb76e8f518dfc4f8b011ae Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 09:05:37 -0600 Subject: [PATCH 079/141] Check for errors after running modcheck --- .github/workflows/run-tests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 1190f5001a..20e824de3b 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -136,4 +136,10 @@ jobs: - name: Install pyspec requirements run: make install_test - name: Run generators with --modcheck - run: make generate_tests modcheck=true + run: make generate_tests modcheck=true 2>&1 | tee consensustestgen.log + - name: Check for errors + run: | + if grep -q "\[ERROR\]" consensustestgen.log; then + echo "There is an error in the log" + exit 1 + fi From 65b5273c60cb28a02b249eafa2dc99dbded5aa10 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 09:07:21 -0600 Subject: [PATCH 080/141] Fix genesis mods; remove test_initialization --- tests/generators/genesis/main.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 9e82d1c112..7e9d36758b 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -8,13 +8,8 @@ 'validity', ]} - altair_mods = phase_0_mods - - # we have new unconditional lines in `initialize_beacon_state_from_eth1` and we want to test it - _new_bellatrix_mods = {key: 'eth2spec.test.bellatrix.genesis.test_' + key for key in [ - 'initialization', - ]} - bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods) + altair_mods = phase_0_mods # No additional Altair specific genesis tests + bellatrix_mods = altair_mods # No additional Bellatrix specific genesis tests capella_mods = bellatrix_mods # No additional Capella specific genesis tests deneb_mods = capella_mods # No additional Deneb specific genesis tests electra_mods = deneb_mods # No additional Electra specific genesis tests From e29bfb174bbd972ad5d8c2316d2713cc4a536d2e Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 09:11:33 -0600 Subject: [PATCH 081/141] Remove combine_mods import --- tests/generators/genesis/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 7e9d36758b..48ea2ca39a 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -1,4 +1,4 @@ -from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods, check_mods +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, check_mods from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ELECTRA From baf9c36795e7cd0664252d7f5c44c4defa5908ae Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 09:16:17 -0600 Subject: [PATCH 082/141] Fix linter --- tests/generators/genesis/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 48ea2ca39a..12907ab7de 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -9,7 +9,7 @@ ]} altair_mods = phase_0_mods # No additional Altair specific genesis tests - bellatrix_mods = altair_mods # No additional Bellatrix specific genesis tests + bellatrix_mods = altair_mods # No additional Bellatrix specific genesis tests capella_mods = bellatrix_mods # No additional Capella specific genesis tests deneb_mods = capella_mods # No additional Deneb specific genesis tests electra_mods = deneb_mods # No additional Electra specific genesis tests From 2ec6a1c7f1305c3e109d80deba406b6beee1da12 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 09:45:02 -0600 Subject: [PATCH 083/141] Fix configuration table formatting --- specs/electra/p2p-interface.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index 0738a8a41d..130aae47bc 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -33,10 +33,10 @@ The specification of these changes continues in the same format as the network s *[New in Electra:EIP7691]* -| Name | Value | Description | -|------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------| -| `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA` | Maximum number of blob sidecars in a single request | -| `BLOB_SIDECAR_SUBNET_COUNT_ELECTRA` | `9` | The number of blob sidecar subnets used in the gossipsub protocol | +| Name | Value | Description | +|-------------------------------------|----------------------------------------------------------|-------------------------------------------------------------------| +| `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA` | Maximum number of blob sidecars in a single request | +| `BLOB_SIDECAR_SUBNET_COUNT_ELECTRA` | `9` | The number of blob sidecar subnets used in the gossipsub protocol | ### The gossip domain: gossipsub From 3b8b799609064f76afcada2527c58ba356bdd889 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 10:05:12 -0600 Subject: [PATCH 084/141] Introduce TARGET_BLOBS_PER_BLOCK_ELECTRA --- configs/mainnet.yaml | 2 ++ configs/minimal.yaml | 4 +++- specs/electra/beacon-chain.md | 1 + .../eth2spec/test/electra/unittests/test_config_invariants.py | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 3a6873a678..159f77024a 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -162,6 +162,8 @@ MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 # `uint64(9)` MAX_BLOBS_PER_BLOCK_ELECTRA: 9 +# `uint64(6)` +TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 6560304ff7..0676ed9a4b 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -156,13 +156,15 @@ MAX_REQUEST_BLOB_SIDECARS: 768 # Electra # [customized] 2**6 * 10**9 (= 64,000,000,000) -MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 +MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 # [customized] 2**7 * 10**9 (= 128,000,000,000) MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 # `9` BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 # `uint64(9)` MAX_BLOBS_PER_BLOCK_ELECTRA: 9 +# `uint64(6)` +TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index c0dd098031..becabce788 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -207,6 +207,7 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | | `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP-7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | +| `TARGET_BLOBS_PER_BLOCK_ELECTRA` | `uint64(6)` | *[New in Electra:EIP-7691]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_ELECTRA` | ### Validator cycle diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py index ce4b6684a4..4e3b909806 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py @@ -19,6 +19,7 @@ def test_processing_pending_partial_withdrawals(spec): @spec_test @single_phase def test_networking(spec): + assert spec.config.TARGET_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOBS_PER_BLOCK_ELECTRA assert spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA == From 488c8aaeb6100e762634563b2fc740a5b695f0be Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 11:43:45 -0600 Subject: [PATCH 085/141] Give target compounding creds in failure cases --- .../test_process_consolidation_request.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py index 0d975e1d99..636c75aad0 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py @@ -11,6 +11,7 @@ ) from eth2spec.test.helpers.withdrawals import ( set_eth1_withdrawal_credential_with_balance, + set_compounding_withdrawal_credential_with_balance, set_compounding_withdrawal_credential, ) @@ -573,7 +574,7 @@ def test_incorrect_exceed_pending_consolidations_limit(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert len(state.pending_consolidations) == spec.PENDING_CONSOLIDATIONS_LIMIT @@ -608,7 +609,7 @@ def test_incorrect_not_enough_consolidation_churn_available(spec, state): target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert spec.get_consolidation_churn_limit(state) <= spec.MIN_ACTIVATION_BALANCE @@ -642,7 +643,7 @@ def test_incorrect_exited_source(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # exit source spec.initiate_validator_exit(state, source_index) @@ -679,7 +680,7 @@ def test_incorrect_exited_target(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # exit target spec.initiate_validator_exit(state, 1) @@ -715,7 +716,7 @@ def test_incorrect_inactive_source(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # set source validator as not yet activated state.validators[source_index].activation_epoch = spec.FAR_FUTURE_EPOCH @@ -752,7 +753,7 @@ def test_incorrect_inactive_target(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # set target validator as not yet activated state.validators[1].activation_epoch = spec.FAR_FUTURE_EPOCH @@ -787,7 +788,7 @@ def test_incorrect_no_source_execution_withdrawal_credential(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert not spec.has_execution_withdrawal_credential(state.validators[source_index]) @@ -889,7 +890,7 @@ def test_incorrect_incorrect_source_address(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert not state.validators[source_index].withdrawal_credentials[12:] == consolidation.source_address @@ -924,7 +925,7 @@ def test_incorrect_unknown_source_pubkey(spec, state): source_pubkey=b"\x00" * 48, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert not state.validators[source_index].pubkey == consolidation.source_pubkey @@ -959,7 +960,7 @@ def test_incorrect_unknown_target_pubkey(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=b"\x00" * 48, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the the return condition assert not state.validators[target_index].pubkey == consolidation.target_pubkey @@ -994,7 +995,7 @@ def test_incorrect_source_has_pending_withdrawal(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Create pending withdrawal pending_withdrawal = spec.PendingPartialWithdrawal( @@ -1033,7 +1034,7 @@ def test_incorrect_source_not_active_long_enough(spec, state): source_pubkey=state.validators[source_index].pubkey, target_pubkey=state.validators[target_index].pubkey, ) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Check the return condition assert current_epoch < state.validators[source_index].activation_epoch + spec.config.SHARD_COMMITTEE_PERIOD From 3c212bc63e32814c655344b56199eb48b4ca17a4 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 13:11:12 -0600 Subject: [PATCH 086/141] Fix mistake --- .../eth2spec/test/electra/unittests/test_config_invariants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py index 4e3b909806..ab9ac149be 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py @@ -19,7 +19,7 @@ def test_processing_pending_partial_withdrawals(spec): @spec_test @single_phase def test_networking(spec): - assert spec.config.TARGET_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOBS_PER_BLOCK_ELECTRA + assert spec.config.TARGET_BLOBS_PER_BLOCK_ELECTRA <= spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA assert spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA == From d332e19d62c57d0f7fdbfc8362f84b5a3949e3b8 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:04:49 -0600 Subject: [PATCH 087/141] Bump version to 1.5.0-alpha.10 --- tests/core/pyspec/eth2spec/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index e3af99e3c0..e7fd637b5a 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.5.0-alpha.9 +1.5.0-alpha.10 From 91bf0290de36b668c1079a95ef38bc37eb91d4b4 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 15:52:13 -0600 Subject: [PATCH 088/141] Fix networking generator modules --- tests/generators/networking/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/generators/networking/main.py b/tests/generators/networking/main.py index 312e03eae7..52b94929f7 100644 --- a/tests/generators/networking/main.py +++ b/tests/generators/networking/main.py @@ -5,8 +5,7 @@ if __name__ == "__main__": eip7594_mods = {key: 'eth2spec.test.eip7594.networking.test_' + key for key in [ - 'compute_columns_for_custody_group', - 'get_custody_groups', + 'get_custody_columns', ]} all_mods = { EIP7594: eip7594_mods From 42588ce4d1ba5c3d6a0fca55e34c85e6a85f3c71 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Dec 2024 15:57:25 -0600 Subject: [PATCH 089/141] Remove unused neg_polynomialcoeff function --- .../eip7594/polynomial-commitments-sampling.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 36f208bbf4..f3844756cb 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -24,7 +24,6 @@ - [Polynomials in coefficient form](#polynomials-in-coefficient-form) - [`polynomial_eval_to_coeff`](#polynomial_eval_to_coeff) - [`add_polynomialcoeff`](#add_polynomialcoeff) - - [`neg_polynomialcoeff`](#neg_polynomialcoeff) - [`multiply_polynomialcoeff`](#multiply_polynomialcoeff) - [`divide_polynomialcoeff`](#divide_polynomialcoeff) - [`interpolate_polynomialcoeff`](#interpolate_polynomialcoeff) @@ -252,16 +251,6 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ``` -#### `neg_polynomialcoeff` - -```python -def neg_polynomialcoeff(a: PolynomialCoeff) -> PolynomialCoeff: - """ - Negative of coefficient form polynomial ``a``. - """ - return PolynomialCoeff([-x for x in a]) -``` - #### `multiply_polynomialcoeff` ```python From bdb1757e81385b76acb8c09002a3bef8694d870a Mon Sep 17 00:00:00 2001 From: Katya Ryazantseva Date: Wed, 4 Dec 2024 09:18:27 +0700 Subject: [PATCH 090/141] fix randrange --- tests/core/pyspec/eth2spec/test/helpers/multi_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 5c64d8cb43..e5dad3a147 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -275,7 +275,7 @@ def get_random_execution_requests(spec, state, rng): def get_random_deposits_requests(spec, state, rng, num_deposits=None): if num_deposits is None: - num_deposits = rng.randrange(0, spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD) + num_deposits = rng.randint(0, spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD) deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))] From db25c9db3a3d89b0fc760ef1bf2e54912a0743ee Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 4 Dec 2024 07:49:46 -0600 Subject: [PATCH 091/141] Use 16-bit random value in validator filter --- specs/electra/beacon-chain.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 543782b71c..ec1c954e5d 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -418,7 +418,7 @@ class BeaconState(Container): #### Modified `compute_proposer_index` -*Note*: The function `compute_proposer_index` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA`. +*Note*: The function `compute_proposer_index` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` and to use a 16-bit random value instead of an 8-bit random byte in the effective balance filter. ```python def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex: @@ -426,15 +426,18 @@ def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex] Return from ``indices`` a random index sampled by effective balance. """ assert len(indices) > 0 - MAX_RANDOM_BYTE = 2**8 - 1 + MAX_RANDOM_VALUE = 2**16 - 1 # [Modified in Electra] i = uint64(0) total = uint64(len(indices)) while True: candidate_index = indices[compute_shuffled_index(i % total, total, seed)] - random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] + # [Modified in Electra] + random_bytes = hash(seed + uint_to_bytes(i // 16)) + offset = i % 16 * 2 + random_value = bytes_to_uint64(random_bytes[offset:offset + 2]) effective_balance = state.validators[candidate_index].effective_balance # [Modified in Electra:EIP7251] - if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte: + if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value: return candidate_index i += 1 ``` @@ -607,7 +610,7 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V #### Modified `get_next_sync_committee_indices` -*Note*: The function `get_next_sync_committee_indices` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA`. +*Note*: The function `get_next_sync_committee_indices` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` and to use a 16-bit random value instead of an 8-bit random byte in the effective balance filter. ```python def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]: @@ -616,19 +619,22 @@ def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorInd """ epoch = Epoch(get_current_epoch(state) + 1) - MAX_RANDOM_BYTE = 2**8 - 1 + MAX_RANDOM_VALUE = 2**16 - 1 # [Modified in Electra] active_validator_indices = get_active_validator_indices(state, epoch) active_validator_count = uint64(len(active_validator_indices)) seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE) - i = 0 + i = uint64(0) sync_committee_indices: List[ValidatorIndex] = [] while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE: shuffled_index = compute_shuffled_index(uint64(i % active_validator_count), active_validator_count, seed) candidate_index = active_validator_indices[shuffled_index] - random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] + # [Modified in Electra] + random_bytes = hash(seed + uint_to_bytes(i // 16)) + offset = i % 16 * 2 + random_value = bytes_to_uint64(random_bytes[offset:offset + 2]) effective_balance = state.validators[candidate_index].effective_balance # [Modified in Electra:EIP7251] - if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte: + if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value: sync_committee_indices.append(candidate_index) i += 1 return sync_committee_indices From 9e085e41c9950bacf0f73c80888a5f5227a58ef2 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 4 Dec 2024 14:12:13 -0600 Subject: [PATCH 092/141] Move target_blobs_per_block to NewPayloadRequest --- specs/_features/eip7594/beacon-chain.md | 1 + specs/_features/eip7732/beacon-chain.md | 1 + specs/electra/beacon-chain.md | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index 7ba88aa882..ffee297942 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -53,6 +53,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, + target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, ) ) # Cache execution payload header diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 2303e33d40..df25fb43ac 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -705,6 +705,7 @@ def process_execution_payload(state: BeaconState, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=requests, + target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, ) ) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 8e65b66df3..d61228bd31 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1004,6 +1004,7 @@ class NewPayloadRequest(object): versioned_hashes: Sequence[VersionedHash] parent_beacon_block_root: Root execution_requests: ExecutionRequests # [New in Electra] + target_blobs_per_block: uint64 # [New in Electra:EIP7742] ``` #### Engine APIs @@ -1058,7 +1059,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, execution_payload = new_payload_request.execution_payload parent_beacon_block_root = new_payload_request.parent_beacon_block_root execution_requests_list = get_execution_requests_list(new_payload_request.execution_requests) # [New in Electra] - target_blobs_per_block = MAX_BLOBS_PER_BLOCK // 2 # [New in Electra:EIP7742] + target_blobs_per_block = new_payload_request.target_blobs_per_block # [New in Electra:EIP7742] if b'' in execution_payload.transactions: return False @@ -1241,6 +1242,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, # [New in Electra] + target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra:EIP7742] ) ) # Cache execution payload header From d3a1c74033a337f21a6c1cb34916bb3a58f0311c Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 5 Dec 2024 11:37:48 +0600 Subject: [PATCH 093/141] Fix lint --- .../epoch_processing/test_process_pending_consolidations.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index 61b3e248aa..f7af296584 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -244,7 +244,8 @@ def test_pending_consolidation_compounding_creds(spec, state): assert state.balances[target_index] == expected_target_balance # All source balance is active and moved to the target, # because the source validator has compounding credentials - assert state.balances[source_index] == state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE + assert state.balances[source_index] == ( + state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE) assert state.pending_consolidations == [] # Pending balance deposit to the target is not created, @@ -300,7 +301,8 @@ def test_pending_consolidation_with_pending_deposit(spec, state): spec.MIN_ACTIVATION_BALANCE + state_before_consolidation.balances[target_index] ) assert state.balances[target_index] == expected_target_balance - assert state.balances[source_index] == state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE + assert state.balances[source_index] == ( + state_before_consolidation.balances[source_index] - spec.MIN_ACTIVATION_BALANCE) assert state.pending_consolidations == [] # Pending deposit to the source was not processed. From 5205a87e0c5456f244c24e92156b832c5af43c03 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 5 Dec 2024 20:12:49 +0600 Subject: [PATCH 094/141] Add more extensive balance computation tests --- .../test_process_pending_consolidations.py | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index f7af296584..26a85cfd2b 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -436,3 +436,110 @@ def test_pending_consolidation_source_balance_greater_than_max_effective_compoun assert state.balances[target_index] == pre_balance_target + source_max_effective_balance assert state.balances[source_index] == excess_source_balance assert state.pending_consolidations == [] + + +# ******************************* +# * CONSOLIDATION BALANCE TESTS * +# ******************************* + + +def prepare_consolidation_and_state(spec, state, source_index, target_index, + creds_type, balance_to_eb, eb_to_min_ab, eb_to_max_eb): + assert creds_type in ['comp', 'eth1'] + assert balance_to_eb in ['<', '=', '>'] + assert eb_to_min_ab in ['<', '=', '>'] + assert eb_to_max_eb in ['<', '='] + if creds_type == 'eth1': + assert eb_to_min_ab == eb_to_max_eb + else: + assert (eb_to_min_ab, eb_to_max_eb) in [('<', '<'), ('=', '<'), ('>', '<'), ('>', '=')] + + # append pending consolidation + current_epoch = spec.get_current_epoch(state) + state.pending_consolidations.append( + spec.PendingConsolidation(source_index=source_index, target_index=target_index) + ) + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + + # Set source and target withdrawal credentials + if creds_type == 'eth1': + set_eth1_withdrawal_credential_with_balance(spec, state, source_index) + else: + set_compounding_withdrawal_credential_with_balance(spec, state, source_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) + + # Set source balances + source = state.validators[source_index] + max_eb = spec.get_max_effective_balance(source) + if eb_to_min_ab == '<': + source.effective_balance = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT + elif eb_to_min_ab == '=': + source.effective_balance = spec.MIN_ACTIVATION_BALANCE + elif eb_to_max_eb == '<': + source.effective_balance = (spec.MAX_EFFECTIVE_BALANCE_ELECTRA - spec.MIN_ACTIVATION_BALANCE) // 2 + else: + source.effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + + if balance_to_eb == '<': + state.balances[source_index] = source.effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 2 + elif balance_to_eb == '=': + state.balances[source_index] = source.effective_balance + else: + state.balances[source_index] = source.effective_balance + spec.EFFECTIVE_BALANCE_INCREMENT // 2 + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_balance_computation_eth1(spec, state): + max_index = 0 + for balance_to_eb in ['<', '=', '>']: + for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '=')]: + source_index = max_index + target_index = max_index + 1 + prepare_consolidation_and_state( + spec, state, source_index, target_index, + 'eth1', balance_to_eb, eb_to_min_ab, eb_to_max_eb + ) + max_index += 2 + + pre_state = state.copy() + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Check balances are moved correctly + for source_index in range(0, max_index, 2): + target_index = source_index + 1 + consolidated_balance = min( + pre_state.validators[source_index].effective_balance, pre_state.balances[source_index] + ) + assert state.balances[source_index] == pre_state.balances[source_index] - consolidated_balance + assert state.balances[target_index] == pre_state.balances[target_index] + consolidated_balance + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_balance_computation_compounding(spec, state): + max_index = 0 + for balance_to_eb in ['<', '=', '>']: + for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '<'), ('>', '<'), ('>', '=')]: + source_index = max_index + target_index = max_index + 1 + prepare_consolidation_and_state( + spec, state, source_index, target_index, + 'comp', balance_to_eb, eb_to_min_ab, eb_to_max_eb + ) + max_index += 2 + + pre_state = state.copy() + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Check balances are moved correctly + for source_index in range(0, max_index, 2): + target_index = source_index + 1 + consolidated_balance = min( + pre_state.validators[source_index].effective_balance, pre_state.balances[source_index] + ) + assert state.balances[source_index] == pre_state.balances[source_index] - consolidated_balance + assert state.balances[target_index] == pre_state.balances[target_index] + consolidated_balance From 41313fe66c06ab949042e9193939dbd2cb30ca33 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 5 Dec 2024 20:22:40 +0600 Subject: [PATCH 095/141] Refactor balance computation tests --- .../test_process_pending_consolidations.py | 55 ++++++++----------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index 26a85cfd2b..dd8ded7316 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -489,19 +489,15 @@ def prepare_consolidation_and_state(spec, state, source_index, target_index, state.balances[source_index] = source.effective_balance + spec.EFFECTIVE_BALANCE_INCREMENT // 2 -@with_electra_and_later -@spec_state_test -def test_pending_consolidation_balance_computation_eth1(spec, state): +def run_balance_computation_test(spec, state, instance_tuples): max_index = 0 - for balance_to_eb in ['<', '=', '>']: - for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '=')]: - source_index = max_index - target_index = max_index + 1 - prepare_consolidation_and_state( - spec, state, source_index, target_index, - 'eth1', balance_to_eb, eb_to_min_ab, eb_to_max_eb - ) - max_index += 2 + for creds_type, balance_to_eb, eb_to_min_ab, eb_to_max_eb in instance_tuples: + source_index = max_index + target_index = max_index + 1 + prepare_consolidation_and_state( + spec, state, source_index, target_index, creds_type, balance_to_eb, eb_to_min_ab, eb_to_max_eb + ) + max_index += 2 pre_state = state.copy() @@ -517,29 +513,24 @@ def test_pending_consolidation_balance_computation_eth1(spec, state): assert state.balances[target_index] == pre_state.balances[target_index] + consolidated_balance + @with_electra_and_later @spec_state_test -def test_pending_consolidation_balance_computation_compounding(spec, state): - max_index = 0 +def test_pending_consolidation_balance_computation_eth1(spec, state): + instances = [] for balance_to_eb in ['<', '=', '>']: - for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '<'), ('>', '<'), ('>', '=')]: - source_index = max_index - target_index = max_index + 1 - prepare_consolidation_and_state( - spec, state, source_index, target_index, - 'comp', balance_to_eb, eb_to_min_ab, eb_to_max_eb - ) - max_index += 2 + for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '=')]: + instances.append(('eth1', balance_to_eb, eb_to_min_ab, eb_to_max_eb)) - pre_state = state.copy() + yield from run_balance_computation_test(spec, state, instances) - yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") - # Check balances are moved correctly - for source_index in range(0, max_index, 2): - target_index = source_index + 1 - consolidated_balance = min( - pre_state.validators[source_index].effective_balance, pre_state.balances[source_index] - ) - assert state.balances[source_index] == pre_state.balances[source_index] - consolidated_balance - assert state.balances[target_index] == pre_state.balances[target_index] + consolidated_balance +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_balance_computation_compounding(spec, state): + instances = [] + for balance_to_eb in ['<', '=', '>']: + for eb_to_min_ab, eb_to_max_eb in [('<', '<'), ('=', '<'), ('>', '<'), ('>', '=')]: + instances.append(('comp', balance_to_eb, eb_to_min_ab, eb_to_max_eb)) + + yield from run_balance_computation_test(spec, state, instances) From 6c5b60f3bc4d3079d57690a83acf76254e3d8b07 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 5 Dec 2024 20:42:48 +0600 Subject: [PATCH 096/141] Fix lint --- .../test_process_pending_consolidations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index dd8ded7316..3dac3040d9 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -461,7 +461,7 @@ def prepare_consolidation_and_state(spec, state, source_index, target_index, ) # Set withdrawable epoch to current epoch to allow processing state.validators[source_index].withdrawable_epoch = current_epoch - + # Set source and target withdrawal credentials if creds_type == 'eth1': set_eth1_withdrawal_credential_with_balance(spec, state, source_index) @@ -477,9 +477,10 @@ def prepare_consolidation_and_state(spec, state, source_index, target_index, elif eb_to_min_ab == '=': source.effective_balance = spec.MIN_ACTIVATION_BALANCE elif eb_to_max_eb == '<': - source.effective_balance = (spec.MAX_EFFECTIVE_BALANCE_ELECTRA - spec.MIN_ACTIVATION_BALANCE) // 2 + source.effective_balance = (max_eb - spec.MIN_ACTIVATION_BALANCE) // 2 else: - source.effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + # eb_to_max_eb == '=' + source.effective_balance = max_eb if balance_to_eb == '<': state.balances[source_index] = source.effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 2 @@ -513,7 +514,6 @@ def run_balance_computation_test(spec, state, instance_tuples): assert state.balances[target_index] == pre_state.balances[target_index] + consolidated_balance - @with_electra_and_later @spec_state_test def test_pending_consolidation_balance_computation_eth1(spec, state): From 349febe9e7f80c36661b384d5fa992aba610c9ac Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 11:26:10 -0600 Subject: [PATCH 097/141] Use TARGET_BLOBS_PER_BLOCK in NewPayloadRequest --- specs/_features/eip7594/beacon-chain.md | 2 +- specs/_features/eip7732/beacon-chain.md | 2 +- specs/electra/validator.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index ffee297942..71986cef2e 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -53,7 +53,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, - target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, ) ) # Cache execution payload header diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index df25fb43ac..4703caa175 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -705,7 +705,7 @@ def process_execution_payload(state: BeaconState, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=requests, - target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, ) ) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 77476cf394..2a5dacbdfc 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -176,7 +176,7 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra:EIP7742] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] max_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] ) return execution_engine.notify_forkchoice_updated( From 2439a4c3071e45fa0100b4a39d914e40b5406774 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 11:31:16 -0600 Subject: [PATCH 098/141] Use Electra config variables --- specs/_features/eip7594/beacon-chain.md | 2 +- specs/_features/eip7732/beacon-chain.md | 2 +- specs/electra/validator.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index 71986cef2e..7dca19d05b 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -53,7 +53,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, ) ) # Cache execution payload header diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 4703caa175..bac64274ee 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -705,7 +705,7 @@ def process_execution_payload(state: BeaconState, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, ) ) diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 2a5dacbdfc..f8882227c7 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -176,8 +176,8 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] - max_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra:EIP7742] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] + max_blobs_per_block=MAX_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From 9df5d98cc378201a52ccfed50b8778a35b2e3d34 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 11:42:00 -0600 Subject: [PATCH 099/141] Set target_blobs_per_block for Electra --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index f33d4eb3bc..adb3706bce 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1251,7 +1251,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, # [New in Electra] - target_blobs_per_block=MAX_BLOBS_PER_BLOCK // 2, # [New in Electra:EIP7742] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] ) ) # Cache execution payload header From f44f1e71e854e2d35781e54102acdf2ca6e0ddfc Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 11:43:51 -0600 Subject: [PATCH 100/141] Put TARGET_BLOBS_PER_BLOCK before MAX_BLOBS_PER_BLOCK --- configs/mainnet.yaml | 4 ++-- configs/minimal.yaml | 4 ++-- specs/electra/beacon-chain.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index f691995228..c43359c521 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -160,10 +160,10 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 # `9` BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 -# `uint64(9)` -MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # `uint64(6)` TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 +# `uint64(9)` +MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index c20b8ef735..56f26bea6a 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -161,10 +161,10 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 # `9` BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 -# `uint64(9)` -MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # `uint64(6)` TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 +# `uint64(9)` +MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index adb3706bce..acb1ff9d74 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -206,8 +206,8 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | -| `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP-7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | | `TARGET_BLOBS_PER_BLOCK_ELECTRA` | `uint64(6)` | *[New in Electra:EIP-7691]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_ELECTRA` | +| `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP-7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | ### Validator cycle From e44bcfa90b494d52538e66a0afadbde4f729d58b Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 12:57:06 -0600 Subject: [PATCH 101/141] Make necessary changes for EIP7594 spec Previous to this commit, the max blob count for EIP7594 was 8. Now that we have raised the target/max to 6/9 for Electra, the max blob count for EIP7594 no longer makes sense. I've raised the target/max for it to 9/12 as a placeholder. This also serves as an example of what changes are necessary to increase the blob count in the future. --- configs/mainnet.yaml | 5 +- configs/minimal.yaml | 5 +- specs/_features/eip7594/beacon-chain.md | 5 +- specs/_features/eip7594/validator.md | 68 +++++++++++++++++++ .../unittests/test_config_invariants.py | 1 + 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 specs/_features/eip7594/validator.md diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index c43359c521..f010bec54d 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -180,9 +180,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -MAX_BLOBS_PER_BLOCK_EIP7594: 8 +TARGET_BLOBS_PER_BLOCK_EIP7594: 9 +MAX_BLOBS_PER_BLOCK_EIP7594: 12 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` -MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 +MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1536 # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 56f26bea6a..449dd3c421 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -179,9 +179,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -MAX_BLOBS_PER_BLOCK_EIP7594: 8 +TARGET_BLOBS_PER_BLOCK_EIP7594: 9 +MAX_BLOBS_PER_BLOCK_EIP7594: 12 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` -MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024 +MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1536 # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/_features/eip7594/beacon-chain.md index 7dca19d05b..8f30e683e7 100644 --- a/specs/_features/eip7594/beacon-chain.md +++ b/specs/_features/eip7594/beacon-chain.md @@ -27,7 +27,8 @@ | Name | Value | Description | | - | - | - | -| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | +| `TARGET_BLOBS_PER_BLOCK_EIP7594` | `uint64(9)` | *[New in EIP7594]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_EIP7594` | +| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(12)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | #### Execution payload @@ -53,7 +54,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] ) ) # Cache execution payload header diff --git a/specs/_features/eip7594/validator.md b/specs/_features/eip7594/validator.md new file mode 100644 index 0000000000..0fddad4ebe --- /dev/null +++ b/specs/_features/eip7594/validator.md @@ -0,0 +1,68 @@ +# EIP7594 -- Honest Validator + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Block proposal](#block-proposal) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [Execution payload](#execution-payload) + + + + +## Introduction + +This document represents the changes to be made in the code of an "honest validator" to implement EIP7594. + +## Prerequisites + +This document is an extension of the [Electra -- Honest Validator](../electra/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 [EIP7594](./beacon-chain.md) are requisite for this document and used throughout. +Please see related Beacon Chain doc before continuing and use them as a reference throughout. + +## Block proposal + +### Constructing the `BeaconBlockBody` + +#### Execution payload + +`prepare_execution_payload` is updated from the Electra specs. + +*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. +That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. + +``python +def prepare_execution_payload(state: BeaconState, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + execution_engine: ExecutionEngine) -> Optional[PayloadId]: + # Verify consistency of the parent hash with respect to the previous execution payload header + parent_hash = state.latest_execution_payload_header.block_hash + + # Set the forkchoice head and initiate the payload build process + withdrawals, _ = get_expected_withdrawals(state) + + 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=withdrawals, + parent_beacon_block_root=hash_tree_root(state.latest_block_header), + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] + max_blobs_per_block=MAX_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] + ) + 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, + ) +``` \ No newline at end of file diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py index 33eaada407..624976a350 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py @@ -31,6 +31,7 @@ def test_polynomical_commitments_sampling(spec): @spec_test @single_phase def test_networking(spec): + assert spec.config.TARGET_BLOBS_PER_BLOCK_EIP7594 <= spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 == From bfc49d8de4cad2c91dadb7208741559ad495d888 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 13:00:13 -0600 Subject: [PATCH 102/141] Change EIP-7691 to EIP7691 in spec comments --- specs/electra/beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index acb1ff9d74..5fd8816a85 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -206,8 +206,8 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | -| `TARGET_BLOBS_PER_BLOCK_ELECTRA` | `uint64(6)` | *[New in Electra:EIP-7691]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_ELECTRA` | -| `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP-7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | +| `TARGET_BLOBS_PER_BLOCK_ELECTRA` | `uint64(6)` | *[New in Electra:EIP7691]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_ELECTRA` | +| `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | ### Validator cycle From f63f6e42698037d68654735a88923e71c3ccffd3 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 13:11:40 -0600 Subject: [PATCH 103/141] Bump BlobSidecarsBy* for EIP7594 to v4 --- specs/_features/eip7594/p2p-interface.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 1b5963dc52..65356a2e49 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -211,9 +211,9 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi #### Messages -##### BlobSidecarsByRoot v3 +##### BlobSidecarsByRoot v4 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/3/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/4/` *[Updated in EIP7594]* @@ -223,6 +223,8 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | +| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | | `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: @@ -245,9 +247,9 @@ Response Content: No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. -##### BlobSidecarsByRange v3 +##### BlobSidecarsByRange v4 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/3/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/4/` *[Updated in EIP7594]* @@ -257,6 +259,8 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | +| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | | `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: From c544029d13949e5e19cbec9f048f122f05f5deb4 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 13:16:02 -0600 Subject: [PATCH 104/141] Revert "Bump BlobSidecarsBy* for EIP7594 to v4" This reverts commit f63f6e42698037d68654735a88923e71c3ccffd3. --- specs/_features/eip7594/p2p-interface.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 65356a2e49..1b5963dc52 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -211,9 +211,9 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi #### Messages -##### BlobSidecarsByRoot v4 +##### BlobSidecarsByRoot v3 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/4/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/3/` *[Updated in EIP7594]* @@ -223,8 +223,6 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| -| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | -| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | | `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: @@ -247,9 +245,9 @@ Response Content: No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. -##### BlobSidecarsByRange v4 +##### BlobSidecarsByRange v3 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/4/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/3/` *[Updated in EIP7594]* @@ -259,8 +257,6 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------| -| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | -| `ELECTRA_FORK_VERSION` | `electra.BlobSidecar` | | `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | Request Content: From 455bb9858478d391229b7216d32672c4a1ab3a03 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 15:59:49 -0600 Subject: [PATCH 105/141] Fix "updated in ..." notes in p2p specs --- specs/electra/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index 63ed422521..ec7f8a63fe 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -105,7 +105,7 @@ The following validations are removed: **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` -*[Updated in ]* +*[Updated in Electra:EIP7691]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -140,7 +140,7 @@ No more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` may be requested at a time. **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` -*[Updated in ]* +*[Updated in Electra:EIP7691]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: From 373e11161c95e53df1e60d259a2c0bd7109a1699 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 5 Dec 2024 16:02:33 -0600 Subject: [PATCH 106/141] Change "updated" to "modified" --- specs/_features/eip7594/p2p-interface.md | 4 ++-- specs/electra/p2p-interface.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 1b5963dc52..1f8172961e 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -215,7 +215,7 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/3/` -*[Updated in EIP7594]* +*[Modified in EIP7594]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -249,7 +249,7 @@ No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/3/` -*[Updated in EIP7594]* +*[Modified in EIP7594]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index ec7f8a63fe..0016976e93 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -105,7 +105,7 @@ The following validations are removed: **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` -*[Updated in Electra:EIP7691]* +*[Modified in Electra:EIP7691]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -140,7 +140,7 @@ No more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` may be requested at a time. **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/` -*[Updated in Electra:EIP7691]* +*[Modified in Electra:EIP7691]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: From 77cacaa3c4bdd44b57b6f6212da7826fad95fa85 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:25:53 -0600 Subject: [PATCH 107/141] Update new in Electra comment Co-authored-by: Hsiao-Wei Wang --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 5fd8816a85..f4997cd76c 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1251,7 +1251,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, # [New in Electra] - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7691:EIP7742] ) ) # Cache execution payload header From ee135b1b4be35c5fb2fb3c3d13f08adcd64a8235 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 9 Dec 2024 11:40:23 +1300 Subject: [PATCH 108/141] Renaming PendingPartialWithdrawal.index to validator_index --- specs/electra/beacon-chain.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index f4997cd76c..b9d80fea0c 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -239,7 +239,7 @@ class PendingDeposit(Container): ```python class PendingPartialWithdrawal(Container): - index: ValidatorIndex + validator_index: ValidatorIndex amount: Gwei withdrawable_epoch: Epoch ``` @@ -586,7 +586,8 @@ def get_consolidation_churn_limit(state: BeaconState) -> Gwei: ```python def get_pending_balance_to_withdraw(state: BeaconState, validator_index: ValidatorIndex) -> Gwei: return sum( - withdrawal.amount for withdrawal in state.pending_partial_withdrawals if withdrawal.index == validator_index + withdrawal.amount for withdrawal in state.pending_partial_withdrawals if + withdrawal.validator_index == validator_index ) ``` @@ -1127,14 +1128,15 @@ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], if withdrawal.withdrawable_epoch > epoch or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: break - validator = state.validators[withdrawal.index] + validator = state.validators[withdrawal.validator_index] has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE - has_excess_balance = state.balances[withdrawal.index] > MIN_ACTIVATION_BALANCE + has_excess_balance = state.balances[withdrawal.validator_index] > MIN_ACTIVATION_BALANCE if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance: - withdrawable_balance = min(state.balances[withdrawal.index] - MIN_ACTIVATION_BALANCE, withdrawal.amount) + withdrawable_balance = min( + state.balances[withdrawal.validator_index] - MIN_ACTIVATION_BALANCE, withdrawal.amount) withdrawals.append(Withdrawal( index=withdrawal_index, - validator_index=withdrawal.index, + validator_index=withdrawal.validator_index, address=ExecutionAddress(validator.withdrawal_credentials[12:]), amount=withdrawable_balance, )) From 757a73bd70f032557aaf2e16aac8e6a86e3154ba Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 9 Dec 2024 11:59:55 +1300 Subject: [PATCH 109/141] Renaming PendingPartialWithdrawal.index to validator_index --- specs/electra/beacon-chain.md | 2 +- .../test_process_consolidation_request.py | 2 +- .../test_process_voluntary_exit.py | 2 +- .../test_process_withdrawal_request.py | 16 ++++++++-------- .../block_processing/test_process_withdrawals.py | 16 ++++++++-------- .../pyspec/eth2spec/test/helpers/withdrawals.py | 4 ++-- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index b9d80fea0c..bcca2a8efe 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1571,7 +1571,7 @@ def process_withdrawal_request( exit_queue_epoch = compute_exit_epoch_and_update_churn(state, to_withdraw) withdrawable_epoch = Epoch(exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY) state.pending_partial_withdrawals.append(PendingPartialWithdrawal( - index=index, + validator_index=index, amount=to_withdraw, withdrawable_epoch=withdrawable_epoch, )) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py index 636c75aad0..3703b9f0f5 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation_request.py @@ -999,7 +999,7 @@ def test_incorrect_source_has_pending_withdrawal(spec, state): # Create pending withdrawal pending_withdrawal = spec.PendingPartialWithdrawal( - index=0, amount=excess_balance, withdrawable_epoch=current_epoch + validator_index=0, amount=excess_balance, withdrawable_epoch=current_epoch ) state.pending_partial_withdrawals.append(pending_withdrawal) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_voluntary_exit.py index eb2d86e6f9..2f9cf81ca4 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_voluntary_exit.py @@ -401,7 +401,7 @@ def test_invalid_validator_has_pending_withdrawal(spec, state): state.pending_partial_withdrawals.append( spec.PendingPartialWithdrawal( - index=validator_index, + validator_index=validator_index, amount=1, withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch), ) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py index 9b125afc17..786094981b 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py @@ -81,7 +81,7 @@ def run_withdrawal_request_processing( + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY ) expected_partial_withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, + validator_index=validator_index, amount=expected_amount_to_withdraw, withdrawable_epoch=expected_withdrawable_epoch, ) @@ -196,7 +196,7 @@ def test_basic_withdrawal_request_with_full_partial_withdrawal_queue(spec, state # Fill the partial withdrawal queue to the max (with a different validator index) partial_withdrawal = spec.PendingPartialWithdrawal( - index=1, amount=1, withdrawable_epoch=current_epoch + validator_index=1, amount=1, withdrawable_epoch=current_epoch ) state.pending_partial_withdrawals = [ partial_withdrawal @@ -353,7 +353,7 @@ def test_unknown_pubkey(spec, state): @with_electra_and_later @spec_state_test @with_presets([MINIMAL]) -def test_basic_partial_withdrawal_request(spec, state): +def test_basic_partial_withdrawal_request(spec, state): rng = random.Random(1344) state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) @@ -471,7 +471,7 @@ def test_partial_withdrawal_request_with_pending_withdrawals(spec, state): # Add pending withdrawals partial_withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, amount=amount, withdrawable_epoch=current_epoch + validator_index=validator_index, amount=amount, withdrawable_epoch=current_epoch ) state.pending_partial_withdrawals = [partial_withdrawal] * 2 @@ -513,7 +513,7 @@ def test_partial_withdrawal_request_with_pending_withdrawals_and_high_amount( # Add many pending withdrawals partial_withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, + validator_index=validator_index, amount=spec.EFFECTIVE_BALANCE_INCREMENT, withdrawable_epoch=current_epoch, ) @@ -661,7 +661,7 @@ def test_partial_withdrawal_queue_full(spec, state): # Fill the partial withdrawal queue to the max partial_withdrawal = spec.PendingPartialWithdrawal( - index=1, amount=1, withdrawable_epoch=current_epoch + validator_index=1, amount=1, withdrawable_epoch=current_epoch ) state.pending_partial_withdrawals = [ partial_withdrawal @@ -746,7 +746,7 @@ def test_pending_withdrawals_consume_all_excess_balance(spec, state): # Add pending withdrawals totalling an amount equal to the excess balance partial_withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, amount=amount, withdrawable_epoch=current_epoch + validator_index=validator_index, amount=amount, withdrawable_epoch=current_epoch ) state.pending_partial_withdrawals = [partial_withdrawal] * 10 @@ -951,7 +951,7 @@ def test_full_exit_request_has_partial_withdrawal(spec, state): state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE_ELECTRA state.pending_partial_withdrawals.append( spec.PendingPartialWithdrawal( - index=validator_index, + validator_index=validator_index, amount=1, withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch), ) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawals.py index 1757c79994..ed3d914154 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawals.py @@ -91,14 +91,14 @@ def test_success_excess_balance_but_no_max_effective_balance_compounding(spec, s @with_electra_and_later @spec_state_test def test_pending_withdrawals_one_skipped_one_effective(spec, state): - index_0 = 3 - index_1 = 5 + validator_index_0 = 3 + validator_index_1 = 5 - pending_withdrawal_0 = prepare_pending_withdrawal(spec, state, index_0) - pending_withdrawal_1 = prepare_pending_withdrawal(spec, state, index_1) + pending_withdrawal_0 = prepare_pending_withdrawal(spec, state, validator_index_0) + pending_withdrawal_1 = prepare_pending_withdrawal(spec, state, validator_index_1) # If validator doesn't have an excess balance pending withdrawal is skipped - state.balances[index_0] = spec.MIN_ACTIVATION_BALANCE + state.balances[validator_index_0] = spec.MIN_ACTIVATION_BALANCE execution_payload = build_empty_execution_payload(spec, state) assert state.pending_partial_withdrawals == [pending_withdrawal_0, pending_withdrawal_1] @@ -155,7 +155,7 @@ def test_pending_withdrawals_exiting_validator(spec, state): validator_index = len(state.validators) // 2 pending_withdrawal = prepare_pending_withdrawal(spec, state, validator_index) - spec.initiate_validator_exit(state, pending_withdrawal.index) + spec.initiate_validator_exit(state, pending_withdrawal.validator_index) execution_payload = build_empty_execution_payload(spec, state) yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) @@ -169,7 +169,7 @@ def test_pending_withdrawals_low_effective_balance(spec, state): validator_index = len(state.validators) // 2 pending_withdrawal = prepare_pending_withdrawal(spec, state, validator_index) - state.validators[pending_withdrawal.index].effective_balance = ( + state.validators[pending_withdrawal.validator_index].effective_balance = ( spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT ) @@ -185,7 +185,7 @@ def test_pending_withdrawals_no_excess_balance(spec, state): validator_index = len(state.validators) // 2 pending_withdrawal = prepare_pending_withdrawal(spec, state, validator_index) - state.balances[pending_withdrawal.index] = spec.MIN_ACTIVATION_BALANCE + state.balances[pending_withdrawal.validator_index] = spec.MIN_ACTIVATION_BALANCE execution_payload = build_empty_execution_payload(spec, state) yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) diff --git a/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py b/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py index 71f8b5ebb8..1c9dec0060 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py @@ -120,7 +120,7 @@ def prepare_pending_withdrawal(spec, state, validator_index, ) withdrawal = spec.PendingPartialWithdrawal( - index=validator_index, + validator_index=validator_index, amount=amount, withdrawable_epoch=withdrawable_epoch, ) @@ -238,7 +238,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with assert len(pending_withdrawal_requests) <= len(execution_payload.withdrawals) for index, request in enumerate(pending_withdrawal_requests): withdrawal = execution_payload.withdrawals[index] - assert withdrawal.validator_index == request.index + assert withdrawal.validator_index == request.validator_index assert withdrawal.amount == request.amount return expected_withdrawals From 2cd9c687cceffb877a0240a159024a43b51e0d39 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 9 Dec 2024 12:17:28 +1300 Subject: [PATCH 110/141] Fix lint --- .../electra/block_processing/test_process_withdrawal_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py index 786094981b..aba6a29332 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_withdrawal_request.py @@ -353,7 +353,7 @@ def test_unknown_pubkey(spec, state): @with_electra_and_later @spec_state_test @with_presets([MINIMAL]) -def test_basic_partial_withdrawal_request(spec, state): +def test_basic_partial_withdrawal_request(spec, state): rng = random.Random(1344) state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) From f4989470c5429e4cd635a10eb32363e1b548360f Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 9 Dec 2024 12:29:05 +1300 Subject: [PATCH 111/141] PR comments by jtraglia --- specs/electra/beacon-chain.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index bcca2a8efe..e5536b8298 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -586,8 +586,8 @@ def get_consolidation_churn_limit(state: BeaconState) -> Gwei: ```python def get_pending_balance_to_withdraw(state: BeaconState, validator_index: ValidatorIndex) -> Gwei: return sum( - withdrawal.amount for withdrawal in state.pending_partial_withdrawals if - withdrawal.validator_index == validator_index + withdrawal.amount for withdrawal in state.pending_partial_withdrawals + if withdrawal.validator_index == validator_index ) ``` @@ -1133,7 +1133,8 @@ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], has_excess_balance = state.balances[withdrawal.validator_index] > MIN_ACTIVATION_BALANCE if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance: withdrawable_balance = min( - state.balances[withdrawal.validator_index] - MIN_ACTIVATION_BALANCE, withdrawal.amount) + state.balances[withdrawal.validator_index] - MIN_ACTIVATION_BALANCE, + withdrawal.amount) withdrawals.append(Withdrawal( index=withdrawal_index, validator_index=withdrawal.validator_index, From ca0801d0d47938f6d0d72fddafe873cb2bed38e9 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 9 Dec 2024 17:38:14 +1300 Subject: [PATCH 112/141] Remove trailing whitespace --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index e5536b8298..d40e89e2c5 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -586,7 +586,7 @@ def get_consolidation_churn_limit(state: BeaconState) -> Gwei: ```python def get_pending_balance_to_withdraw(state: BeaconState, validator_index: ValidatorIndex) -> Gwei: return sum( - withdrawal.amount for withdrawal in state.pending_partial_withdrawals + withdrawal.amount for withdrawal in state.pending_partial_withdrawals if withdrawal.validator_index == validator_index ) ``` From 1c659a96dfe85c13f3d7c3ba8a35bf40cc80d692 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 10 Dec 2024 16:59:24 -0600 Subject: [PATCH 113/141] Fix some issues in new random execution requests --- .../eth2spec/test/helpers/multi_operations.py | 60 +++++++------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index e5dad3a147..4d6e8a2138 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -260,9 +260,9 @@ def run_test_full_random_operations(spec, state, rng=Random(2080)): def get_random_execution_requests(spec, state, rng): - deposits = get_random_deposits_requests(spec, state, rng) - withdrawals = get_random_withdrawals_requests(spec, state, rng) - consolidations = get_random_consolidations_requests(spec, state, rng) + deposits = get_random_deposit_requests(spec, state, rng) + withdrawals = get_random_withdrawal_requests(spec, state, rng) + consolidations = get_random_consolidation_requests(spec, state, rng) execution_requests = spec.ExecutionRequests( deposits=deposits, @@ -273,19 +273,17 @@ def get_random_execution_requests(spec, state, rng): return execution_requests -def get_random_deposits_requests(spec, state, rng, num_deposits=None): +def get_random_deposit_requests(spec, state, rng, num_deposits=None): if num_deposits is None: num_deposits = rng.randint(0, spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD) deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))] - deposits_requests = [] - - for i in range(num_deposits): + deposit_requests = [] + for _ in range(num_deposits): index = rng.randrange(0, num_deposits) withdrawal_pubkey = pubkeys[index] withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] - deposit, _, _ = build_deposit( spec, deposit_data_leaves, @@ -295,78 +293,60 @@ def get_random_deposits_requests(spec, state, rng, num_deposits=None): withdrawal_credentials=withdrawal_credentials, signed=True, ) - - deposit_request = spec.DepositRequest( + deposit_requests.append(spec.DepositRequest( pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount, signature=deposit.data.signature, - index=deposit.data.index, - ) - - deposits_requests.append(deposit_request) + index=rng.randrange(0, 2**64), + )) - return deposits_requests + return deposit_requests -def get_random_withdrawals_requests(spec, state, rng, num_withdrawals=None): +def get_random_withdrawal_requests(spec, state, rng, num_withdrawals=None): if num_withdrawals is None: num_withdrawals = rng.randint(0, spec.MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD) - withdrawals_requests = [] - - state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - current_epoch = spec.get_current_epoch(state) active_validator_indices = spec.get_active_validator_indices(state, current_epoch) + withdrawal_requests = [] for _ in range(num_withdrawals): if not active_validator_indices: break address = rng.getrandbits(160).to_bytes(20, 'big') - validator_index = rng.choice(active_validator_indices) validator = state.validators[validator_index] validator_balance = state.balances[validator_index] - - withdrawal_request = spec.WithdrawalRequest( + withdrawal_requests.append(spec.WithdrawalRequest( source_address=address, validator_pubkey=validator.pubkey, amount=rng.randint(0, validator_balance), - ) - - withdrawals_requests.append(withdrawal_request) + )) - return withdrawals_requests + return withdrawal_requests -def get_random_consolidations_requests(spec, state, rng, num_consolidations=None): +def get_random_consolidation_requests(spec, state, rng, num_consolidations=None): if num_consolidations is None: num_consolidations = rng.randint(0, spec.MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD) - consolidations_requests = [] - - state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - current_epoch = spec.get_current_epoch(state) active_validator_indices = spec.get_active_validator_indices(state, current_epoch) + consolidation_requests = [] for _ in range(num_consolidations): source_address = rng.getrandbits(160).to_bytes(20, 'big') - source_index = rng.choice(active_validator_indices) target_index = rng.choice(active_validator_indices) - source_validator = state.validators[source_index] target_validator = state.validators[target_index] - - consolidation_request = spec.ConsolidationRequest( + consolidation_requests.append(spec.ConsolidationRequest( source_address=source_address, source_pubkey=source_validator.pubkey, target_pubkey=target_validator.pubkey, - ) - - consolidations_requests.append(consolidation_request) + )) - return consolidations_requests + return consolidation_requests From d216321d663ed39dccbbfdf224eae8ec0cbe6218 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:06:35 -0500 Subject: [PATCH 114/141] Move eip7594 directory to new fulu directory --- specs/{_features/eip7594 => fulu}/beacon-chain.md | 0 specs/{_features/eip7594 => fulu}/das-core.md | 0 specs/{_features/eip7594 => fulu}/fork-choice.md | 0 specs/{_features/eip7594 => fulu}/fork.md | 0 specs/{_features/eip7594 => fulu}/p2p-interface.md | 0 specs/{_features/eip7594 => fulu}/peer-sampling.md | 0 .../eip7594 => fulu}/polynomial-commitments-sampling.md | 0 specs/{_features/eip7594 => fulu}/validator.md | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename specs/{_features/eip7594 => fulu}/beacon-chain.md (100%) rename specs/{_features/eip7594 => fulu}/das-core.md (100%) rename specs/{_features/eip7594 => fulu}/fork-choice.md (100%) rename specs/{_features/eip7594 => fulu}/fork.md (100%) rename specs/{_features/eip7594 => fulu}/p2p-interface.md (100%) rename specs/{_features/eip7594 => fulu}/peer-sampling.md (100%) rename specs/{_features/eip7594 => fulu}/polynomial-commitments-sampling.md (100%) rename specs/{_features/eip7594 => fulu}/validator.md (100%) diff --git a/specs/_features/eip7594/beacon-chain.md b/specs/fulu/beacon-chain.md similarity index 100% rename from specs/_features/eip7594/beacon-chain.md rename to specs/fulu/beacon-chain.md diff --git a/specs/_features/eip7594/das-core.md b/specs/fulu/das-core.md similarity index 100% rename from specs/_features/eip7594/das-core.md rename to specs/fulu/das-core.md diff --git a/specs/_features/eip7594/fork-choice.md b/specs/fulu/fork-choice.md similarity index 100% rename from specs/_features/eip7594/fork-choice.md rename to specs/fulu/fork-choice.md diff --git a/specs/_features/eip7594/fork.md b/specs/fulu/fork.md similarity index 100% rename from specs/_features/eip7594/fork.md rename to specs/fulu/fork.md diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/fulu/p2p-interface.md similarity index 100% rename from specs/_features/eip7594/p2p-interface.md rename to specs/fulu/p2p-interface.md diff --git a/specs/_features/eip7594/peer-sampling.md b/specs/fulu/peer-sampling.md similarity index 100% rename from specs/_features/eip7594/peer-sampling.md rename to specs/fulu/peer-sampling.md diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/fulu/polynomial-commitments-sampling.md similarity index 100% rename from specs/_features/eip7594/polynomial-commitments-sampling.md rename to specs/fulu/polynomial-commitments-sampling.md diff --git a/specs/_features/eip7594/validator.md b/specs/fulu/validator.md similarity index 100% rename from specs/_features/eip7594/validator.md rename to specs/fulu/validator.md From 761eabbb3350c80095312a7e6affa8ced8275956 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:12:57 -0500 Subject: [PATCH 115/141] Rename some EIP7594 names to Fulu --- specs/fulu/das-core.md | 2 +- specs/fulu/fork-choice.md | 4 +-- specs/fulu/fork.md | 31 +++++++++---------- specs/fulu/p2p-interface.md | 14 ++++----- specs/fulu/peer-sampling.md | 4 +-- specs/fulu/polynomial-commitments-sampling.md | 2 +- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/specs/fulu/das-core.md b/specs/fulu/das-core.md index b3e8a23a48..25576bc1f4 100644 --- a/specs/fulu/das-core.md +++ b/specs/fulu/das-core.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Data Availability Sampling Core +# Fulu -- Data Availability Sampling Core **Notice**: This document is a work-in-progress for researchers and implementers. diff --git a/specs/fulu/fork-choice.md b/specs/fulu/fork-choice.md index ed91ab1d46..8677254e78 100644 --- a/specs/fulu/fork-choice.md +++ b/specs/fulu/fork-choice.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Fork Choice +# Fulu -- Fork Choice ## Table of contents @@ -67,7 +67,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: ) assert store.finalized_checkpoint.root == finalized_checkpoint_block - # [Modified in EIP7594] + # [Modified in Fulu:EIP7594] assert is_data_available(hash_tree_root(block)) # Check the block is valid and compute the post-state diff --git a/specs/fulu/fork.md b/specs/fulu/fork.md index 4f2c17561f..e496467212 100644 --- a/specs/fulu/fork.md +++ b/specs/fulu/fork.md @@ -1,4 +1,4 @@ -# EIP7594 -- Fork Logic +# Fulu -- Fork Logic **Notice**: This document is a work-in-progress for researchers and implementers. @@ -12,7 +12,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to EIP7594](#fork-to-eip7594) +- [Fork to Fulu](#fork-to-fulu) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) @@ -20,7 +20,7 @@ ## Introduction -This document describes the process of EIP7594 upgrade. +This document describes the process of Fulu upgrade. ## Configuration @@ -28,8 +28,8 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP7594_FORK_VERSION` | `Version('0x06000000')` | -| `EIP7594_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | +| `FULU_FORK_VERSION` | `Version('0x06000000')` | +| `FULU_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | ## Helper functions @@ -42,8 +42,8 @@ def compute_fork_version(epoch: Epoch) -> Version: """ Return the fork version at the given ``epoch``. """ - if epoch >= EIP7594_FORK_EPOCH: - return EIP7594_FORK_VERSION + if epoch >= FULU_FORK_EPOCH: + return FULU_FORK_VERSION if epoch >= ELECTRA_FORK_EPOCH: return ELECTRA_FORK_VERSION if epoch >= DENEB_FORK_EPOCH: @@ -57,23 +57,22 @@ def compute_fork_version(epoch: Epoch) -> Version: return GENESIS_FORK_VERSION ``` -## Fork to EIP7594 +## Fork to Fulu ### Fork trigger -EIP7594 does not need a hard fork. We only add this fork doc for compiling this new feature in pyspec. +TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. +For now, we assume the condition will be triggered at epoch `FULU_FORK_EPOCH`. -For now, we assume the condition will be triggered at epoch `EIP7594_FORK_EPOCH`. - -Note that for the pure EIP7594 networks, we don't apply `upgrade_to_eip7594` since it starts with EIP7594 version logic. +Note that for the pure Fulu networks, we don't apply `upgrade_to_fulu` since it starts with Fulu version logic. ### Upgrading the state -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7594_FORK_EPOCH`, -an irregular state change is made to upgrade to EIP7594. +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == FULU_FORK_EPOCH`, +an irregular state change is made to upgrade to Fulu. ```python -def upgrade_to_eip7594(pre: electra.BeaconState) -> BeaconState: +def upgrade_to_fulu(pre: electra.BeaconState) -> BeaconState: epoch = electra.get_current_epoch(pre) post = BeaconState( # Versioning @@ -82,7 +81,7 @@ def upgrade_to_eip7594(pre: electra.BeaconState) -> BeaconState: slot=pre.slot, fork=Fork( previous_version=pre.fork.current_version, - current_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] + current_version=FULU_FORK_VERSION, # [Modified in Fulu] epoch=epoch, ), # History diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index 1f8172961e..3df35ef223 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Networking +# Fulu -- Networking **Notice**: This document is a work-in-progress for researchers and implementers. @@ -57,7 +57,7 @@ The specification of these changes continues in the same format as the network s ### Configuration -*[New in EIP7594]* +*[New in Fulu:EIP7594]* | Name | Value | Description | |------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------| @@ -284,7 +284,7 @@ Clients MUST respond with at least the blob sidecars of the first blob-carrying **Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_root/1/` -*[New in EIP7594]* +*[New in Fulu:EIP7594]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -292,7 +292,7 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------------| -| `EIP7594_FORK_VERSION` | `eip7594.DataColumnSidecar` | +| `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | Request Content: @@ -321,7 +321,7 @@ No more than `MAX_REQUEST_DATA_COLUMN_SIDECARS` may be requested at a time. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `DataColumnSidecar` payload. -Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, EIP7594_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the data column sidecar in the response. +Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, FULU_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the data column sidecar in the response. Clients MUST respond with at least one sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. @@ -340,7 +340,7 @@ The `` field is calculated as `context = compute_fork_digest(fork | `fork_version` | Chunk SSZ type | |------------------------|-----------------------------| -| `EIP7594_FORK_VERSION` | `eip7594.DataColumnSidecar` | +| `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | Request Content: @@ -371,7 +371,7 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `DataColumnSidecar` payload. -Let `data_column_serve_range` be `[max(current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, EIP7594_FORK_EPOCH), current_epoch]`. +Let `data_column_serve_range` be `[max(current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, FULU_FORK_EPOCH), current_epoch]`. Clients MUST keep a record of data column sidecars seen on the epoch range `data_column_serve_range` where `current_epoch` is defined by the current wall-clock time, and clients MUST support serving requests of data columns on this range. diff --git a/specs/fulu/peer-sampling.md b/specs/fulu/peer-sampling.md index 853bf88ff0..d8b05bba13 100644 --- a/specs/fulu/peer-sampling.md +++ b/specs/fulu/peer-sampling.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Peer Sampling +# Fulu -- Peer Sampling **Notice**: This document is a work-in-progress for researchers and implementers. @@ -23,7 +23,7 @@ ## Introduction -The purpose of this document is to complement [EIP-7594 -- Data Availability Sampling Core](das-core.md) by specifying the peer sampling functionality of the full PeerDAS protocol. Initially, this functionality may not be implemented by all clients. In such cases, it is replaced by [subnet sampling](das-core.md#subnet-sampling), which is an extension of the custody component of the protocol. +The purpose of this document is to complement [Fulu -- Data Availability Sampling Core](das-core.md) by specifying the peer sampling functionality of the full PeerDAS protocol. Initially, this functionality may not be implemented by all clients. In such cases, it is replaced by [subnet sampling](das-core.md#subnet-sampling), which is an extension of the custody component of the protocol. ## Helper functions diff --git a/specs/fulu/polynomial-commitments-sampling.md b/specs/fulu/polynomial-commitments-sampling.md index f3844756cb..c85e870896 100644 --- a/specs/fulu/polynomial-commitments-sampling.md +++ b/specs/fulu/polynomial-commitments-sampling.md @@ -1,4 +1,4 @@ -# EIP-7594 -- Polynomial Commitments Sampling +# Fulu -- Polynomial Commitments Sampling ## Table of contents From 14bfa7897d3da52c9d97f115a7d463c810a140f9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:15:35 -0500 Subject: [PATCH 116/141] Rename & fixup spec builder --- pysetup/spec_builders/__init__.py | 4 ++-- pysetup/spec_builders/{eip7594.py => fulu.py} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename pysetup/spec_builders/{eip7594.py => fulu.py} (95%) diff --git a/pysetup/spec_builders/__init__.py b/pysetup/spec_builders/__init__.py index c5bbcf39eb..f6e05fc5b9 100644 --- a/pysetup/spec_builders/__init__.py +++ b/pysetup/spec_builders/__init__.py @@ -4,8 +4,8 @@ from .capella import CapellaSpecBuilder from .deneb import DenebSpecBuilder from .electra import ElectraSpecBuilder +from .fulu import FuluSpecBuilder from .whisk import WhiskSpecBuilder -from .eip7594 import EIP7594SpecBuilder from .eip6800 import EIP6800SpecBuilder from .eip7732 import EIP7732SpecBuilder @@ -14,6 +14,6 @@ builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - ElectraSpecBuilder, WhiskSpecBuilder, EIP7594SpecBuilder, EIP6800SpecBuilder, EIP7732SpecBuilder, + ElectraSpecBuilder, FuluSpecBuilder, WhiskSpecBuilder, EIP6800SpecBuilder, EIP7732SpecBuilder, ) } diff --git a/pysetup/spec_builders/eip7594.py b/pysetup/spec_builders/fulu.py similarity index 95% rename from pysetup/spec_builders/eip7594.py rename to pysetup/spec_builders/fulu.py index e3177da8ca..3cd0c1c467 100644 --- a/pysetup/spec_builders/eip7594.py +++ b/pysetup/spec_builders/fulu.py @@ -1,11 +1,11 @@ from typing import Dict from .base import BaseSpecBuilder -from ..constants import EIP7594 +from ..constants import FULU -class EIP7594SpecBuilder(BaseSpecBuilder): - fork: str = EIP7594 +class FuluSpecBuilder(BaseSpecBuilder): + fork: str = FULU @classmethod def imports(cls, preset_name: str): From 28719cdebf322ab09870043cdb603e1950724d1f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:19:42 -0500 Subject: [PATCH 117/141] Rename eip7594 to fulu, p1 --- .circleci/config.yml | 12 ++++---- .github/workflows/run-tests.yml | 2 +- .gitignore | 2 +- Makefile | 2 +- pysetup/constants.py | 2 +- scripts/build_run_docker_tests.sh | 2 +- tests/core/pyspec/eth2spec/test/context.py | 2 +- .../merkle_proof/test_single_merkle_proof.py | 6 ++-- .../networking/test_get_custody_columns.py | 20 ++++++------- .../test/eip7594/unittests/das/test_das.py | 20 ++++++------- .../test_polynomial_commitments.py | 18 +++++------ .../unittests/test_config_invariants.py | 6 ++-- .../test/eip7594/unittests/test_custody.py | 10 +++---- .../test/eip7594/unittests/test_networking.py | 30 +++++++++---------- .../test/eip7594/unittests/test_security.py | 4 +-- .../pyspec/eth2spec/test/helpers/constants.py | 2 +- .../pyspec/eth2spec/test/utils/kzg_tests.py | 2 +- tests/generators/kzg_7594/main.py | 2 +- tests/generators/merkle_proof/main.py | 10 +++---- tests/generators/networking/main.py | 6 ++-- 20 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17db49b3a9..80d44bef37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: command: make citest fork=electra - store_test_results: path: tests/core/pyspec/test-reports - test-whisk: + test-fulu: docker: - image: cimg/python:3.12.4 working_directory: ~/specs-repo @@ -165,10 +165,10 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=whisk + command: make citest fork=fulu - store_test_results: path: tests/core/pyspec/test-reports - test-eip7594: + test-whisk: docker: - image: cimg/python:3.12.4 working_directory: ~/specs-repo @@ -178,7 +178,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=eip7594 + command: make citest fork=whisk - store_test_results: path: tests/core/pyspec/test-reports table_of_contents: @@ -239,10 +239,10 @@ workflows: - test-electra: requires: - install_pyspec_test - - test-whisk: + - test-fulu: requires: - install_pyspec_test - - test-eip7594: + - test-whisk: requires: - install_pyspec_test - table_of_contents diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 20e824de3b..84c5d9cee8 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -86,7 +86,7 @@ jobs: needs: [lint,codespell,table_of_contents] strategy: matrix: - version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "whisk", "eip7594"] + version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "fulu", "whisk"] steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index ad62aa177e..57cd180030 100644 --- a/.gitignore +++ b/.gitignore @@ -22,8 +22,8 @@ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/electra/ +tests/core/pyspec/eth2spec/fulu/ tests/core/pyspec/eth2spec/whisk/ -tests/core/pyspec/eth2spec/eip7594/ tests/core/pyspec/eth2spec/eip6800/ tests/core/pyspec/eth2spec/eip7732/ diff --git a/Makefile b/Makefile index 7a3ebbf6c6..48b1b4fbf6 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk eip6800 eip7594 eip7732 +ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra fulu whisk eip6800 eip7732 # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) diff --git a/pysetup/constants.py b/pysetup/constants.py index 6bf22865b2..0959e795c4 100644 --- a/pysetup/constants.py +++ b/pysetup/constants.py @@ -5,7 +5,7 @@ CAPELLA = 'capella' DENEB = 'deneb' ELECTRA = 'electra' -EIP7594 = 'eip7594' +FULU = 'fulu' EIP6800 = 'eip6800' WHISK = 'whisk' EIP7732 = 'eip7732' diff --git a/scripts/build_run_docker_tests.sh b/scripts/build_run_docker_tests.sh index 91aa2c8ae1..1716a4774c 100755 --- a/scripts/build_run_docker_tests.sh +++ b/scripts/build_run_docker_tests.sh @@ -10,7 +10,7 @@ # Set variables -ALL_EXECUTABLE_SPECS=("phase0" "altair" "bellatrix" "capella" "deneb" "electra" "whisk" "eip7594") +ALL_EXECUTABLE_SPECS=("phase0" "altair" "bellatrix" "capella" "deneb" "electra" "fulu" "whisk") TEST_PRESET_TYPE=minimal FORK_TO_TEST=phase0 WORKDIR="//consensus-specs//tests//core//pyspec" diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 8b2e8de6d3..37ca20bb78 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -558,7 +558,7 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_electra_and_later = with_all_phases_from(ELECTRA) with_whisk_and_later = with_all_phases_from(WHISK, all_phases=ALLOWED_TEST_RUNNER_FORKS) -with_eip7594_and_later = with_all_phases_from(EIP7594, all_phases=ALLOWED_TEST_RUNNER_FORKS) +with_fulu_and_later = with_all_phases_from(EIP7594, all_phases=ALLOWED_TEST_RUNNER_FORKS) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py index 4bd5fb4912..b614793f73 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py @@ -2,7 +2,7 @@ from eth2spec.test.context import ( spec_state_test, - with_eip7594_and_later, + with_fulu_and_later, with_test_suite_name, ) from eth2spec.test.helpers.block import ( @@ -62,14 +62,14 @@ def _run_blob_kzg_commitments_merkle_proof_test(spec, state, rng=None): @with_test_suite_name("BeaconBlockBody") -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test def test_blob_kzg_commitments_merkle_proof__basic(spec, state): yield from _run_blob_kzg_commitments_merkle_proof_test(spec, state) @with_test_suite_name("BeaconBlockBody") -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test def test_blob_kzg_commitments_merkle_proof__random_block_1(spec, state): rng = random.Random(1111) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py index 97cc948db5..d3be42ce16 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py @@ -3,7 +3,7 @@ from eth2spec.test.context import ( single_phase, spec_test, - with_eip7594_and_later, + with_fulu_and_later, ) @@ -33,7 +33,7 @@ def _run_get_custody_columns(spec, rng, node_id=None, custody_group_count=None): yield 'result', 'meta', python_list_result -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__min_node_id_min_custody_group_count(spec): @@ -41,7 +41,7 @@ def test_get_custody_columns__min_node_id_min_custody_group_count(spec): yield from _run_get_custody_columns(spec, rng, node_id=0, custody_group_count=0) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__min_node_id_max_custody_group_count(spec): @@ -51,7 +51,7 @@ def test_get_custody_columns__min_node_id_max_custody_group_count(spec): custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__max_node_id_min_custody_group_count(spec): @@ -59,7 +59,7 @@ def test_get_custody_columns__max_node_id_min_custody_group_count(spec): yield from _run_get_custody_columns(spec, rng, node_id=2**256 - 1, custody_group_count=0) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__max_node_id_max_custody_group_count(spec): @@ -70,7 +70,7 @@ def test_get_custody_columns__max_node_id_max_custody_group_count(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__max_node_id_max_custody_group_count_minus_1(spec): @@ -81,7 +81,7 @@ def test_get_custody_columns__max_node_id_max_custody_group_count_minus_1(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__short_node_id(spec): @@ -89,7 +89,7 @@ def test_get_custody_columns__short_node_id(spec): yield from _run_get_custody_columns(spec, rng, node_id=1048576, custody_group_count=1) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__1(spec): @@ -97,7 +97,7 @@ def test_get_custody_columns__1(spec): yield from _run_get_custody_columns(spec, rng) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__2(spec): @@ -105,7 +105,7 @@ def test_get_custody_columns__2(spec): yield from _run_get_custody_columns(spec, rng) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns__3(spec): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py index dd0a80fda4..f18e52b149 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py @@ -4,7 +4,7 @@ spec_test, single_phase, with_config_overrides, - with_eip7594_and_later, + with_fulu_and_later, ) from eth2spec.test.helpers.blob import ( get_sample_blob, @@ -16,7 +16,7 @@ def chunks(lst, n): return [lst[i:i + n] for i in range(0, len(lst), n)] -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_compute_matrix(spec): @@ -41,7 +41,7 @@ def test_compute_matrix(spec): assert blob == input_blobs[blob_index] -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_recover_matrix(spec): @@ -68,7 +68,7 @@ def test_recover_matrix(spec): assert recovered_matrix == matrix -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__1(spec): @@ -77,7 +77,7 @@ def test_get_extended_sample_count__1(spec): spec.get_extended_sample_count(allowed_failures) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__2(spec): @@ -86,7 +86,7 @@ def test_get_extended_sample_count__2(spec): spec.get_extended_sample_count(allowed_failures) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__3(spec): @@ -95,7 +95,7 @@ def test_get_extended_sample_count__3(spec): spec.get_extended_sample_count(allowed_failures) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__lower_bound(spec): @@ -103,7 +103,7 @@ def test_get_extended_sample_count__lower_bound(spec): spec.get_extended_sample_count(allowed_failures) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__upper_bound(spec): @@ -111,7 +111,7 @@ def test_get_extended_sample_count__upper_bound(spec): spec.get_extended_sample_count(allowed_failures) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_extended_sample_count__upper_bound_exceed(spec): @@ -119,7 +119,7 @@ def test_get_extended_sample_count__upper_bound_exceed(spec): expect_assertion_error(lambda: spec.get_extended_sample_count(allowed_failures)) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @with_config_overrides({ 'NUMBER_OF_COLUMNS': 128, diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index 1d72b142af..b935c212e4 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -3,7 +3,7 @@ spec_test, single_phase, expect_assertion_error, - with_eip7594_and_later, + with_fulu_and_later, ) from eth2spec.test.helpers.blob import ( get_sample_blob, @@ -11,7 +11,7 @@ from eth2spec.utils.bls import BLS_MODULUS -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_fft(spec): @@ -45,7 +45,7 @@ def test_fft(spec): assert individual_evaluation == poly_eval[i] -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_coset_fft(spec): @@ -84,7 +84,7 @@ def test_coset_fft(spec): assert individual_evaluation == poly_eval[i] -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_construct_vanishing_polynomial(spec): @@ -108,7 +108,7 @@ def test_construct_vanishing_polynomial(spec): assert all(a != spec.BLSFieldElement(0) for a in zero_poly_eval_brp[start:end]) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_verify_cell_kzg_proof_batch_zero_cells(spec): @@ -121,7 +121,7 @@ def test_verify_cell_kzg_proof_batch_zero_cells(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_verify_cell_kzg_proof_batch(spec): @@ -173,7 +173,7 @@ def test_verify_cell_kzg_proof_batch(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_verify_cell_kzg_proof_batch_invalid(spec): @@ -229,7 +229,7 @@ def test_verify_cell_kzg_proof_batch_invalid(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_recover_cells_and_kzg_proofs(spec): @@ -268,7 +268,7 @@ def test_recover_cells_and_kzg_proofs(spec): assert proofs == recovered_proofs -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_multiply_polynomial_degree_overflow(spec): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py index 624976a350..6be2a3f64c 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py @@ -1,11 +1,11 @@ from eth2spec.test.context import ( single_phase, spec_test, - with_eip7594_and_later, + with_fulu_and_later, ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_invariants(spec): @@ -20,7 +20,7 @@ def test_invariants(spec): ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_polynomical_commitments_sampling(spec): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py index 7e7cef3421..dcd08ce1d2 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py @@ -2,7 +2,7 @@ expect_assertion_error, spec_test, single_phase, - with_eip7594_and_later, + with_fulu_and_later, ) @@ -21,7 +21,7 @@ def run_get_custody_columns(spec, peer_count, custody_group_count): assert len(columns) == len(set(columns)) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns_peers_within_number_of_columns(spec): @@ -31,7 +31,7 @@ def test_get_custody_columns_peers_within_number_of_columns(spec): run_get_custody_columns(spec, peer_count, custody_group_count) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns_peers_more_than_number_of_columns(spec): @@ -41,7 +41,7 @@ def test_get_custody_columns_peers_more_than_number_of_columns(spec): run_get_custody_columns(spec, peer_count, custody_group_count) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns_maximum_groups(spec): @@ -50,7 +50,7 @@ def test_get_custody_columns_maximum_groups(spec): run_get_custody_columns(spec, peer_count, custody_group_count) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_get_custody_columns_custody_size_more_than_number_of_groups(spec): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py index 931cc9c1d1..cb4a9e0f92 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py @@ -3,7 +3,7 @@ single_phase, spec_state_test, spec_test, - with_eip7594_and_later, + with_fulu_and_later, ) from eth2spec.debug.random_value import ( RandomizationMode, @@ -45,7 +45,7 @@ def compute_data_column_sidecar(spec, state): # Tests for verify_data_column_sidecar -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar__valid(spec, state): @@ -53,7 +53,7 @@ def test_verify_data_column_sidecar__valid(spec, state): assert spec.verify_data_column_sidecar(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar__invalid_zero_blobs(spec, state): @@ -64,7 +64,7 @@ def test_verify_data_column_sidecar__invalid_zero_blobs(spec, state): assert not spec.verify_data_column_sidecar(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar__invalid_index(spec, state): @@ -73,7 +73,7 @@ def test_verify_data_column_sidecar__invalid_index(spec, state): assert not spec.verify_data_column_sidecar(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar__invalid_mismatch_len_column(spec, state): @@ -82,7 +82,7 @@ def test_verify_data_column_sidecar__invalid_mismatch_len_column(spec, state): assert not spec.verify_data_column_sidecar(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar__invalid_mismatch_len_kzg_commitments(spec, state): @@ -91,7 +91,7 @@ def test_verify_data_column_sidecar__invalid_mismatch_len_kzg_commitments(spec, assert not spec.verify_data_column_sidecar(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecars__invalid_mismatch_len_kzg_proofs(spec, state): @@ -103,7 +103,7 @@ def test_verify_data_column_sidecars__invalid_mismatch_len_kzg_proofs(spec, stat # Tests for verify_data_column_sidecar_kzg_proofs -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_kzg_proofs__valid(spec, state): @@ -111,7 +111,7 @@ def test_verify_data_column_sidecar_kzg_proofs__valid(spec, state): assert spec.verify_data_column_sidecar_kzg_proofs(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_column(spec, state): @@ -120,7 +120,7 @@ def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_column(spec, state assert not spec.verify_data_column_sidecar_kzg_proofs(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_commitment(spec, state): @@ -129,7 +129,7 @@ def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_commitment(spec, s assert not spec.verify_data_column_sidecar_kzg_proofs(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_proof(spec, state): @@ -141,7 +141,7 @@ def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_proof(spec, state) # Tests for verify_data_column_sidecar_inclusion_proof -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_inclusion_proof__valid(spec, state): @@ -149,7 +149,7 @@ def test_verify_data_column_sidecar_inclusion_proof__valid(spec, state): assert spec.verify_data_column_sidecar_inclusion_proof(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_inclusion_proof__invalid_missing_commitment(spec, state): @@ -158,7 +158,7 @@ def test_verify_data_column_sidecar_inclusion_proof__invalid_missing_commitment( assert not spec.verify_data_column_sidecar_inclusion_proof(sidecar) -@with_eip7594_and_later +@with_fulu_and_later @spec_state_test @single_phase def test_verify_data_column_sidecar_inclusion_proof__invalid_duplicate_commitment(spec, state): @@ -170,7 +170,7 @@ def test_verify_data_column_sidecar_inclusion_proof__invalid_duplicate_commitmen # Tests for compute_subnet_for_data_column_sidecar -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_compute_subnet_for_data_column_sidecar(spec): diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py index 282433b9c9..d93560d037 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py @@ -1,7 +1,7 @@ from eth2spec.test.context import ( spec_test, single_phase, - with_eip7594_and_later, + with_fulu_and_later, with_phases, ) from eth2spec.test.helpers.constants import ( @@ -9,7 +9,7 @@ ) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase @with_phases([MAINNET]) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 284dc32f03..3130e64d7f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -18,8 +18,8 @@ CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') ELECTRA = SpecForkName('electra') +FULU = SpecForkName('fulu') WHISK = SpecForkName('whisk') -EIP7594 = SpecForkName('eip7594') EIP7732 = SpecForkName('eip7732') # diff --git a/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py index 071efd4a2e..7566e9c981 100644 --- a/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py @@ -6,7 +6,7 @@ ) from eth2spec.utils import bls -from eth2spec.eip7594 import spec +from eth2spec.fulu import spec ############################################################################### diff --git a/tests/generators/kzg_7594/main.py b/tests/generators/kzg_7594/main.py index 814a840537..08eb82701f 100644 --- a/tests/generators/kzg_7594/main.py +++ b/tests/generators/kzg_7594/main.py @@ -6,7 +6,7 @@ from eth_utils import encode_hex -from eth2spec.eip7594 import spec +from eth2spec.fulu import spec from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.test.helpers.constants import EIP7594 from eth2spec.test.helpers.typing import SpecForkName diff --git a/tests/generators/merkle_proof/main.py b/tests/generators/merkle_proof/main.py index 9ae985b865..4a787f5737 100644 --- a/tests/generators/merkle_proof/main.py +++ b/tests/generators/merkle_proof/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import DENEB, ELECTRA, EIP7594 +from eth2spec.test.helpers.constants import DENEB, ELECTRA, FULU from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods, check_mods @@ -6,16 +6,16 @@ deneb_mods = {key: 'eth2spec.test.deneb.merkle_proof.test_' + key for key in [ 'single_merkle_proof', ]} - _new_eip7594_mods = {key: 'eth2spec.test.eip7594.merkle_proof.test_' + key for key in [ + electra_mods = deneb_mods + _new_fulu_mods = {key: 'eth2spec.test.fulu.merkle_proof.test_' + key for key in [ 'single_merkle_proof', ]} - electra_mods = deneb_mods - eip_7594_mods = combine_mods(_new_eip7594_mods, electra_mods) + fulu_mods = combine_mods(_new_fulu_mods, electra_mods) all_mods = { DENEB: deneb_mods, ELECTRA: electra_mods, - EIP7594: eip_7594_mods, + FULU: fulu_mods, } check_mods(all_mods, "merkle_proof") diff --git a/tests/generators/networking/main.py b/tests/generators/networking/main.py index 52b94929f7..3217c2cce2 100644 --- a/tests/generators/networking/main.py +++ b/tests/generators/networking/main.py @@ -1,14 +1,14 @@ -from eth2spec.test.helpers.constants import EIP7594 +from eth2spec.test.helpers.constants import FULU from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, check_mods if __name__ == "__main__": - eip7594_mods = {key: 'eth2spec.test.eip7594.networking.test_' + key for key in [ + fulu_mods = {key: 'eth2spec.test.fulu.networking.test_' + key for key in [ 'get_custody_columns', ]} all_mods = { - EIP7594: eip7594_mods + FULU: fulu_mods } check_mods(all_mods, "networking") From 6a306f7c4530536c9b47c17bf67872c1c02d08a0 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:24:22 -0500 Subject: [PATCH 118/141] Rename eip7594 to fulu, p2 --- configs/mainnet.yaml | 8 ++++---- configs/minimal.yaml | 8 ++++---- presets/mainnet/eip7594.yaml | 2 +- presets/minimal/eip7594.yaml | 2 +- pysetup/md_doc_paths.py | 4 ++-- specs/fulu/p2p-interface.md | 8 ++++---- tests/core/pyspec/eth2spec/test/context.py | 4 ++-- .../eth2spec/test/deneb/fork_choice/test_on_block.py | 12 ++++++------ tests/core/pyspec/eth2spec/test/helpers/constants.py | 6 +++--- tests/generators/kzg_7594/main.py | 8 ++++---- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index f010bec54d..403823075c 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,9 +53,9 @@ DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC # Electra ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 # temporary stub -# EIP7594 -EIP7594_FORK_VERSION: 0x06000000 # temporary stub -EIP7594_FORK_EPOCH: 18446744073709551615 +# FULU +FULU_FORK_VERSION: 0x06000000 # temporary stub +FULU_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x08000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 @@ -173,7 +173,7 @@ WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 # `Epoch(2)` WHISK_PROPOSER_SELECTION_GAP: 2 -# EIP7594 +# FULU NUMBER_OF_COLUMNS: 128 NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 449dd3c421..9050339f17 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,9 +52,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # Electra ELECTRA_FORK_VERSION: 0x05000001 ELECTRA_FORK_EPOCH: 18446744073709551615 -# EIP7594 -EIP7594_FORK_VERSION: 0x06000001 -EIP7594_FORK_EPOCH: 18446744073709551615 +# FULU +FULU_FORK_VERSION: 0x06000001 +FULU_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x08000001 WHISK_FORK_EPOCH: 18446744073709551615 @@ -172,7 +172,7 @@ MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 WHISK_PROPOSER_SELECTION_GAP: 1 -# EIP7594 +# FULU NUMBER_OF_COLUMNS: 128 NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 diff --git a/presets/mainnet/eip7594.yaml b/presets/mainnet/eip7594.yaml index 813febf26d..84111aba28 100644 --- a/presets/mainnet/eip7594.yaml +++ b/presets/mainnet/eip7594.yaml @@ -1,4 +1,4 @@ -# Mainnet preset - EIP7594 +# Mainnet preset - FULU # Misc # --------------------------------------------------------------- diff --git a/presets/minimal/eip7594.yaml b/presets/minimal/eip7594.yaml index 847719a421..1204822fb8 100644 --- a/presets/minimal/eip7594.yaml +++ b/presets/minimal/eip7594.yaml @@ -1,4 +1,4 @@ -# Minimal preset - EIP7594 +# Minimal preset - FULU # Misc # --------------------------------------------------------------- diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index 0f0d1c8593..2c4539eeb6 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -8,7 +8,7 @@ DENEB, ELECTRA, WHISK, - EIP7594, + FULU, EIP6800, EIP7732, ) @@ -22,7 +22,7 @@ DENEB: CAPELLA, ELECTRA: DENEB, WHISK: CAPELLA, - EIP7594: ELECTRA, + FULU: ELECTRA, EIP6800: DENEB, EIP7732: ELECTRA, } diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index 3df35ef223..95d6ffbb86 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -9,7 +9,7 @@ - [Introduction](#introduction) -- [Modifications in EIP-7594](#modifications-in-eip-7594) +- [Modifications in Fulu](#modifications-in-fulu) - [Preset](#preset) - [Configuration](#configuration) - [Containers](#containers) @@ -43,11 +43,11 @@ ## Introduction -This document contains the consensus-layer networking specification for EIP7594. +This document contains the consensus-layer networking specification for Fulu. The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. -## Modifications in EIP-7594 +## Modifications in Fulu ### Preset @@ -163,7 +163,7 @@ Where ### The gossip domain: gossipsub -Some gossip meshes are upgraded in the EIP-7594 fork to support upgraded types. +Some gossip meshes are upgraded in the Fulu fork to support upgraded types. #### Topics and messages diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 37ca20bb78..8c960cfc75 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -8,7 +8,7 @@ from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ELECTRA, - EIP7594, + FULU, WHISK, MINIMAL, ALL_PHASES, @@ -558,7 +558,7 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_electra_and_later = with_all_phases_from(ELECTRA) with_whisk_and_later = with_all_phases_from(WHISK, all_phases=ALLOWED_TEST_RUNNER_FORKS) -with_fulu_and_later = with_all_phases_from(EIP7594, all_phases=ALLOWED_TEST_RUNNER_FORKS) +with_fulu_and_later = with_all_phases_from(FULU, all_phases=ALLOWED_TEST_RUNNER_FORKS) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/deneb/fork_choice/test_on_block.py b/tests/core/pyspec/eth2spec/test/deneb/fork_choice/test_on_block.py index 905cb390eb..2845af4634 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/fork_choice/test_on_block.py +++ b/tests/core/pyspec/eth2spec/test/deneb/fork_choice/test_on_block.py @@ -7,7 +7,7 @@ from eth2spec.test.helpers.constants import ( DENEB, - EIP7594, + FULU, ) from eth2spec.test.helpers.block import ( @@ -39,7 +39,7 @@ def get_block_with_blob(spec, state, rng=None): return block, blobs, blob_kzg_proofs -@with_all_phases_from_except(DENEB, [EIP7594]) +@with_all_phases_from_except(DENEB, [FULU]) @spec_state_test def test_simple_blob_data(spec, state): rng = Random(1234) @@ -74,7 +74,7 @@ def test_simple_blob_data(spec, state): yield 'steps', test_steps -@with_all_phases_from_except(DENEB, [EIP7594]) +@with_all_phases_from_except(DENEB, [FULU]) @spec_state_test def test_invalid_incorrect_proof(spec, state): rng = Random(1234) @@ -102,7 +102,7 @@ def test_invalid_incorrect_proof(spec, state): yield 'steps', test_steps -@with_all_phases_from_except(DENEB, [EIP7594]) +@with_all_phases_from_except(DENEB, [FULU]) @spec_state_test def test_invalid_data_unavailable(spec, state): rng = Random(1234) @@ -130,7 +130,7 @@ def test_invalid_data_unavailable(spec, state): yield 'steps', test_steps -@with_all_phases_from_except(DENEB, [EIP7594]) +@with_all_phases_from_except(DENEB, [FULU]) @spec_state_test def test_invalid_wrong_proofs_length(spec, state): rng = Random(1234) @@ -158,7 +158,7 @@ def test_invalid_wrong_proofs_length(spec, state): yield 'steps', test_steps -@with_all_phases_from_except(DENEB, [EIP7594]) +@with_all_phases_from_except(DENEB, [FULU]) @spec_state_test def test_invalid_wrong_blobs_length(spec, state): rng = Random(1234) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 3130e64d7f..627243be87 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -37,12 +37,12 @@ *MAINNET_FORKS, ELECTRA, # Experimental patches - EIP7594, + FULU, ) # The forks that have light client specs LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], ELECTRA) # The forks that output to the test vectors. -TESTGEN_FORKS = (*MAINNET_FORKS, ELECTRA, EIP7594, WHISK) +TESTGEN_FORKS = (*MAINNET_FORKS, ELECTRA, FULU, WHISK) # Forks allowed in the test runner `--fork` flag, to fail fast in case of typos ALLOWED_TEST_RUNNER_FORKS = (*ALL_PHASES, WHISK, EIP7732) @@ -57,7 +57,7 @@ ELECTRA: DENEB, # Experimental patches WHISK: CAPELLA, - EIP7594: ELECTRA, + FULU: ELECTRA, EIP7732: ELECTRA, } diff --git a/tests/generators/kzg_7594/main.py b/tests/generators/kzg_7594/main.py index 08eb82701f..d01ddf2878 100644 --- a/tests/generators/kzg_7594/main.py +++ b/tests/generators/kzg_7594/main.py @@ -8,7 +8,7 @@ from eth2spec.fulu import spec from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing -from eth2spec.test.helpers.constants import EIP7594 +from eth2spec.test.helpers.constants import FULU from eth2spec.test.helpers.typing import SpecForkName from eth2spec.test.utils.kzg_tests import ( CELL_RANDOM_VALID1, @@ -566,7 +566,7 @@ def cases_fn() -> Iterable[gen_typing.TestCase]: bls.use_arkworks() gen_runner.run_generator("kzg_7594", [ # EIP-7594 - create_provider(EIP7594, 'compute_cells_and_kzg_proofs', case_compute_cells_and_kzg_proofs), - create_provider(EIP7594, 'verify_cell_kzg_proof_batch', case_verify_cell_kzg_proof_batch), - create_provider(EIP7594, 'recover_cells_and_kzg_proofs', case_recover_cells_and_kzg_proofs), + create_provider(FULU, 'compute_cells_and_kzg_proofs', case_compute_cells_and_kzg_proofs), + create_provider(FULU, 'verify_cell_kzg_proof_batch', case_verify_cell_kzg_proof_batch), + create_provider(FULU, 'recover_cells_and_kzg_proofs', case_recover_cells_and_kzg_proofs), ]) From 0302dbf75673fda1087db05aed5f2a3717b90cd9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:27:39 -0500 Subject: [PATCH 119/141] Fix order & capitalization --- configs/mainnet.yaml | 24 ++++++++++++------------ configs/minimal.yaml | 20 ++++++++++---------- pysetup/md_doc_paths.py | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 403823075c..c4f3e48c53 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,7 +53,7 @@ DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC # Electra ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 # temporary stub -# FULU +# Fulu FULU_FORK_VERSION: 0x06000000 # temporary stub FULU_FORK_EPOCH: 18446744073709551615 # WHISK @@ -167,23 +167,23 @@ MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 -# Whisk -# `Epoch(2**8)` -WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 -# `Epoch(2)` -WHISK_PROPOSER_SELECTION_GAP: 2 - -# FULU +# Fulu NUMBER_OF_COLUMNS: 128 NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -TARGET_BLOBS_PER_BLOCK_EIP7594: 9 -MAX_BLOBS_PER_BLOCK_EIP7594: 12 -# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` -MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1536 +TARGET_BLOBS_PER_BLOCK_FULU: 9 +MAX_BLOBS_PER_BLOCK_FULU: 12 +# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` +MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 + +# Whisk +# `Epoch(2**8)` +WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 +# `Epoch(2)` +WHISK_PROPOSER_SELECTION_GAP: 2 # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 9050339f17..afb99949a4 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,7 +52,7 @@ DENEB_FORK_EPOCH: 18446744073709551615 # Electra ELECTRA_FORK_VERSION: 0x05000001 ELECTRA_FORK_EPOCH: 18446744073709551615 -# FULU +# Fulu FULU_FORK_VERSION: 0x06000001 FULU_FORK_EPOCH: 18446744073709551615 # WHISK @@ -168,21 +168,21 @@ MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 1152 -# Whisk -WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 -WHISK_PROPOSER_SELECTION_GAP: 1 - -# FULU +# Fulu NUMBER_OF_COLUMNS: 128 NUMBER_OF_CUSTODY_GROUPS: 128 DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -TARGET_BLOBS_PER_BLOCK_EIP7594: 9 -MAX_BLOBS_PER_BLOCK_EIP7594: 12 -# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` -MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1536 +TARGET_BLOBS_PER_BLOCK_FULU: 9 +MAX_BLOBS_PER_BLOCK_FULU: 12 +# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` +MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 + +# Whisk +WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 +WHISK_PROPOSER_SELECTION_GAP: 1 # EIP7732 MAX_REQUEST_PAYLOADS: 128 diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index 2c4539eeb6..ff081ad5ab 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -7,8 +7,8 @@ CAPELLA, DENEB, ELECTRA, - WHISK, FULU, + WHISK, EIP6800, EIP7732, ) @@ -21,8 +21,8 @@ CAPELLA: BELLATRIX, DENEB: CAPELLA, ELECTRA: DENEB, - WHISK: CAPELLA, FULU: ELECTRA, + WHISK: CAPELLA, EIP6800: DENEB, EIP7732: ELECTRA, } From 2106e729bceb4c92f33589350f0cad3ad7cc4c01 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:28:52 -0500 Subject: [PATCH 120/141] Rename files --- presets/mainnet/{eip7594.yaml => fulu.yaml} | 0 presets/minimal/{eip7594.yaml => fulu.yaml} | 0 tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/__init__.py | 0 .../eth2spec/test/{eip7594 => fulu}/merkle_proof/__init__.py | 0 .../{eip7594 => fulu}/merkle_proof/test_single_merkle_proof.py | 0 .../pyspec/eth2spec/test/{eip7594 => fulu}/networking/__init__.py | 0 .../test/{eip7594 => fulu}/networking/test_get_custody_columns.py | 0 .../pyspec/eth2spec/test/{eip7594 => fulu}/unittests/__init__.py | 0 .../eth2spec/test/{eip7594 => fulu}/unittests/das/__init__.py | 0 .../eth2spec/test/{eip7594 => fulu}/unittests/das/test_das.py | 0 .../unittests/polynomial_commitments/__init__.py | 0 .../polynomial_commitments/test_polynomial_commitments.py | 0 .../test/{eip7594 => fulu}/unittests/test_config_invariants.py | 0 .../eth2spec/test/{eip7594 => fulu}/unittests/test_custody.py | 0 .../eth2spec/test/{eip7594 => fulu}/unittests/test_networking.py | 0 .../eth2spec/test/{eip7594 => fulu}/unittests/test_security.py | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename presets/mainnet/{eip7594.yaml => fulu.yaml} (100%) rename presets/minimal/{eip7594.yaml => fulu.yaml} (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/merkle_proof/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/merkle_proof/test_single_merkle_proof.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/networking/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/networking/test_get_custody_columns.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/das/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/das/test_das.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/polynomial_commitments/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/polynomial_commitments/test_polynomial_commitments.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/test_config_invariants.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/test_custody.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/test_networking.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7594 => fulu}/unittests/test_security.py (100%) diff --git a/presets/mainnet/eip7594.yaml b/presets/mainnet/fulu.yaml similarity index 100% rename from presets/mainnet/eip7594.yaml rename to presets/mainnet/fulu.yaml diff --git a/presets/minimal/eip7594.yaml b/presets/minimal/fulu.yaml similarity index 100% rename from presets/minimal/eip7594.yaml rename to presets/minimal/fulu.yaml diff --git a/tests/core/pyspec/eth2spec/test/eip7594/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/merkle_proof/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/merkle_proof/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/fulu/merkle_proof/test_single_merkle_proof.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py rename to tests/core/pyspec/eth2spec/test/fulu/merkle_proof/test_single_merkle_proof.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/networking/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/networking/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/networking/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/networking/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py b/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py rename to tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/das/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/das/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/das/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/das/test_das.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/das/test_das.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/das/test_das.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/__init__.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/polynomial_commitments/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/__init__.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/polynomial_commitments/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/polynomial_commitments/test_polynomial_commitments.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/polynomial_commitments/test_polynomial_commitments.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/test_config_invariants.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/test_custody.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_networking.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/test_networking.py diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_security.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7594/unittests/test_security.py rename to tests/core/pyspec/eth2spec/test/fulu/unittests/test_security.py From f9c1ce519fc389f3e2e184d92e343b529aee6487 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 22 Oct 2024 11:47:07 -0500 Subject: [PATCH 121/141] Update core readme --- README.md | 1 + specs/fulu/fork-choice.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3a57c6256..f7acc28706 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Features are researched and developed in parallel, and then consolidated into se | Seq. | Code Name | Fork Epoch | Specs | | - | - | - | - | | 5 | **Electra** | TBD |
  • Core
    • [Beacon Chain changes](specs/electra/beacon-chain.md)
    • [Electra fork](specs/electra/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/electra/light-client/sync-protocol.md) ([fork](specs/electra/light-client/fork.md), [networking](specs/electra/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/electra/validator.md)
    • [P2P networking](specs/electra/p2p-interface.md)
| +| 6 | **Fulu** | TBD |
  • Core
    • [Fulu fork](specs/fulu/fork.md)
    • [Data availability sampling core](specs/fulu/das-core.md)
    • [Polynomial commitments sampling](specs/fulu/polynomial-commitments-sampling.md)
    • [Fork choice changes](specs/fulu/fork.md)
  • Additions
    • [P2P networking](specs/fulu/p2p-interface.md)
    • [Peer sampling](specs/fulu/peer-sampling.md)
| ### Outdated Specifications diff --git a/specs/fulu/fork-choice.md b/specs/fulu/fork-choice.md index 8677254e78..4a20906804 100644 --- a/specs/fulu/fork-choice.md +++ b/specs/fulu/fork-choice.md @@ -16,7 +16,7 @@ ## Introduction -This is the modification of the fork choice accompanying EIP-7594. +This is the modification of the fork choice accompanying Fulu. ## Helpers From 607547efb9c8b2a8035f03d83acc415e5e201438 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:37:09 -0600 Subject: [PATCH 122/141] Update comments for FULU_FORK_* --- configs/mainnet.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index c4f3e48c53..9972817aca 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -54,8 +54,8 @@ DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 # temporary stub # Fulu -FULU_FORK_VERSION: 0x06000000 # temporary stub -FULU_FORK_EPOCH: 18446744073709551615 +FULU_FORK_VERSION: 0x06000000 +FULU_FORK_EPOCH: 184467440737095516155 # temporary stub # WHISK WHISK_FORK_VERSION: 0x08000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 From f15d116949c1f44463c17cfdccc49174dec02303 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:47:44 -0600 Subject: [PATCH 123/141] Fix mistake --- configs/mainnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 9972817aca..dadb261b44 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -55,7 +55,7 @@ ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 # temporary stub # Fulu FULU_FORK_VERSION: 0x06000000 -FULU_FORK_EPOCH: 184467440737095516155 # temporary stub +FULU_FORK_EPOCH: 18446744073709551615 # temporary stub # WHISK WHISK_FORK_VERSION: 0x08000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 From b504270fb01b041cb3d20adaff7fa365aa4b6777 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 11 Dec 2024 08:57:13 -0600 Subject: [PATCH 124/141] Make changes after rebasing --- specs/fulu/beacon-chain.md | 10 ++--- specs/fulu/p2p-interface.md | 38 +++++++++---------- specs/fulu/validator.md | 10 ++--- .../fulu/unittests/test_config_invariants.py | 10 ++--- .../test/fulu/unittests/test_custody.py | 2 +- .../core/pyspec/eth2spec/test/helpers/blob.py | 6 +-- .../pyspec/eth2spec/test/helpers/forks.py | 10 ++--- .../test/utils/randomized_block_tests.py | 2 +- 8 files changed, 44 insertions(+), 44 deletions(-) diff --git a/specs/fulu/beacon-chain.md b/specs/fulu/beacon-chain.md index 8f30e683e7..5dca6580f5 100644 --- a/specs/fulu/beacon-chain.md +++ b/specs/fulu/beacon-chain.md @@ -1,4 +1,4 @@ -# EIP7594 -- The Beacon Chain +# Fulu -- The Beacon Chain **Notice**: This document is a work-in-progress for researchers and implementers. @@ -27,8 +27,8 @@ | Name | Value | Description | | - | - | - | -| `TARGET_BLOBS_PER_BLOCK_EIP7594` | `uint64(9)` | *[New in EIP7594]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_EIP7594` | -| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(12)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | +| `TARGET_BLOBS_PER_BLOCK_FULU` | `uint64(9)` | *[New in Fulu:EIP7594]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_FULU` | +| `MAX_BLOBS_PER_BLOCK_FULU` | `uint64(12)` | *[New in Fulu:EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | #### Execution payload @@ -45,7 +45,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify commitments are under limit - assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594 # [Modified in EIP7594] + assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_FULU # [Modified in Fulu:EIP7594] # Verify the execution payload is valid versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( @@ -54,7 +54,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] ) ) # Cache execution payload header diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index 95d6ffbb86..7dbb16432c 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -64,7 +64,7 @@ The specification of these changes continues in the same format as the network s | `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `128` | The number of data column sidecar subnets used in the gossipsub protocol | | `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | | `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | -| `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request | +| `MAX_REQUEST_BLOB_SIDECARS_FULU` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` | Maximum number of blob sidecars in a single request | ### Containers @@ -174,7 +174,7 @@ Some gossip meshes are upgraded in the Fulu fork to support upgraded types. *Updated validation* - _[REJECT]_ The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- - i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594` + i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_FULU` ##### Blob subnets @@ -215,21 +215,21 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/3/` -*[Modified in EIP7594]* +*[Modified in Fulu:EIP7594]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|------------------------|-----------------------| -| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|---------------------|--------------------| +| `FULU_FORK_VERSION` | `fulu.BlobSidecar` | Request Content: ``` ( - List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_EIP7594] + List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_FULU] ) ``` @@ -237,27 +237,27 @@ Response Content: ``` ( - List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594] + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_FULU] ) ``` *Updated validation* -No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time. +No more than `MAX_REQUEST_BLOB_SIDECARS_FULU` may be requested at a time. ##### BlobSidecarsByRange v3 **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/3/` -*[Modified in EIP7594]* +*[Modified in Fulu:EIP7594]* The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|------------------------|-----------------------| -| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` | +| `fork_version` | Chunk SSZ type | +|---------------------|--------------------| +| `FULU_FORK_VERSION` | `fulu.BlobSidecar` | Request Content: @@ -272,13 +272,13 @@ Response Content: ``` ( - List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594] + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_FULU] ) ``` *Updated validation* -Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` sidecars. +Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_FULU` sidecars. ##### DataColumnSidecarsByRoot v1 @@ -290,8 +290,8 @@ The `` field is calculated as `context = compute_fork_digest(fork [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|------------------------|-----------------------------| +| `fork_version` | Chunk SSZ type | +|---------------------|--------------------------| | `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | Request Content: @@ -338,8 +338,8 @@ The `` field is calculated as `context = compute_fork_digest(fork [1]: # (eth2spec: skip) -| `fork_version` | Chunk SSZ type | -|------------------------|-----------------------------| +| `fork_version` | Chunk SSZ type | +|---------------------|--------------------------| | `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | Request Content: diff --git a/specs/fulu/validator.md b/specs/fulu/validator.md index 0fddad4ebe..b8781e8ad6 100644 --- a/specs/fulu/validator.md +++ b/specs/fulu/validator.md @@ -1,4 +1,4 @@ -# EIP7594 -- Honest Validator +# Fulu -- Honest Validator ## Table of contents @@ -17,14 +17,14 @@ ## Introduction -This document represents the changes to be made in the code of an "honest validator" to implement EIP7594. +This document represents the changes to be made in the code of an "honest validator" to implement Fulu. ## Prerequisites This document is an extension of the [Electra -- Honest Validator](../electra/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 [EIP7594](./beacon-chain.md) are requisite for this document and used throughout. +All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [Fulu](./beacon-chain.md) are requisite for this document and used throughout. Please see related Beacon Chain doc before continuing and use them as a reference throughout. ## Block proposal @@ -56,8 +56,8 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] - max_blobs_per_block=MAX_BLOBS_PER_BLOCK_EIP7594, # [Modified in EIP7594] + target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] + max_blobs_per_block=MAX_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, diff --git a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py index 6be2a3f64c..57b40f6e2c 100644 --- a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py @@ -27,13 +27,13 @@ def test_polynomical_commitments_sampling(spec): assert spec.FIELD_ELEMENTS_PER_EXT_BLOB == 2 * spec.FIELD_ELEMENTS_PER_BLOB -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_networking(spec): - assert spec.config.TARGET_BLOBS_PER_BLOCK_EIP7594 <= spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 - assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK + assert spec.config.TARGET_BLOBS_PER_BLOCK_FULU <= spec.config.MAX_BLOBS_PER_BLOCK_FULU + assert spec.config.MAX_BLOBS_PER_BLOCK_FULU <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( - spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 == - spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 + spec.config.MAX_REQUEST_BLOB_SIDECARS_FULU == + spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_FULU ) diff --git a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py index dcd08ce1d2..fa2fcbc7dc 100644 --- a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py +++ b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_custody.py @@ -59,7 +59,7 @@ def test_get_custody_columns_custody_size_more_than_number_of_groups(spec): expect_assertion_error(lambda: spec.get_custody_groups(node_id, custody_group_count)) -@with_eip7594_and_later +@with_fulu_and_later @spec_test @single_phase def test_compute_columns_for_custody_group_out_of_bound_custody_group(spec): diff --git a/tests/core/pyspec/eth2spec/test/helpers/blob.py b/tests/core/pyspec/eth2spec/test/helpers/blob.py index e0d82da1a0..f89b1ff527 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/blob.py +++ b/tests/core/pyspec/eth2spec/test/helpers/blob.py @@ -4,7 +4,7 @@ from eth2spec.test.helpers.forks import ( is_post_electra, - is_post_eip7594, + is_post_fulu, ) @@ -107,8 +107,8 @@ def get_sample_blob_tx(spec, blob_count=1, rng=random.Random(5566), is_valid_blo def get_max_blob_count(spec): - if is_post_eip7594(spec): - return spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 + if is_post_fulu(spec): + return spec.config.MAX_BLOBS_PER_BLOCK_FULU elif is_post_electra(spec): return spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA else: diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index e261e3a754..4bb3d54ed3 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,6 +1,6 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - ELECTRA, WHISK, EIP7732, EIP7594, + ELECTRA, FULU, WHISK, EIP7732, PREVIOUS_FORK_OF, ) @@ -41,12 +41,12 @@ def is_post_electra(spec): return is_post_fork(spec.fork, ELECTRA) -def is_post_whisk(spec): - return is_post_fork(spec.fork, WHISK) +def is_post_fulu(spec): + return is_post_fork(spec.fork, FULU) -def is_post_eip7594(spec): - return is_post_fork(spec.fork, EIP7594) +def is_post_whisk(spec): + return is_post_fork(spec.fork, WHISK) def is_post_eip7732(spec): diff --git a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py index df67872880..0e4727b794 100644 --- a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py @@ -251,7 +251,7 @@ def random_block_capella(spec, state, signed_blocks, scenario_state, rng=Random( def random_block_deneb(spec, state, signed_blocks, scenario_state, rng=Random(3456)): block = random_block_capella(spec, state, signed_blocks, scenario_state, rng=rng) # TODO: more commitments. blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] - # TODO: add MAX_BLOBS_PER_BLOCK_EIP7594 at fulu + # TODO: add MAX_BLOBS_PER_BLOCK_FULU at fulu opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx( spec, blob_count=rng.randint(0, spec.config.MAX_BLOBS_PER_BLOCK), rng=rng) block.body.execution_payload.transactions.append(opaque_tx) From 2b75f5f015a52682469a781065688fcc23b7e3fc Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 11 Dec 2024 12:00:17 -0600 Subject: [PATCH 125/141] Fix table formatting --- specs/fulu/p2p-interface.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index 7dbb16432c..abebbffecc 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -59,12 +59,12 @@ The specification of these changes continues in the same format as the network s *[New in Fulu:EIP7594]* -| Name | Value | Description | -|------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------| -| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `128` | The number of data column sidecar subnets used in the gossipsub protocol | -| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | -| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | -| `MAX_REQUEST_BLOB_SIDECARS_FULU` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` | Maximum number of blob sidecars in a single request | +| Name | Value | Description | +|------------------------------------------------|-------------------------------------------------------|---------------------------------------------------------------------------| +| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `128` | The number of data column sidecar subnets used in the gossipsub protocol | +| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request | +| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars | +| `MAX_REQUEST_BLOB_SIDECARS_FULU` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` | Maximum number of blob sidecars in a single request | ### Containers From cb84461215be481a1f2ae68c99555859207983d5 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 11 Dec 2024 12:01:24 -0600 Subject: [PATCH 126/141] Delete unnecessary comments --- tests/generators/kzg_4844/main.py | 1 - tests/generators/kzg_7594/main.py | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/generators/kzg_4844/main.py b/tests/generators/kzg_4844/main.py index a4d3544bdf..2e125ba9d9 100644 --- a/tests/generators/kzg_4844/main.py +++ b/tests/generators/kzg_4844/main.py @@ -598,7 +598,6 @@ def cases_fn() -> Iterable[gen_typing.TestCase]: if __name__ == "__main__": bls.use_arkworks() gen_runner.run_generator("kzg", [ - # DENEB create_provider(DENEB, 'blob_to_kzg_commitment', case01_blob_to_kzg_commitment), create_provider(DENEB, 'compute_kzg_proof', case02_compute_kzg_proof), create_provider(DENEB, 'verify_kzg_proof', case03_verify_kzg_proof), diff --git a/tests/generators/kzg_7594/main.py b/tests/generators/kzg_7594/main.py index d01ddf2878..0c7222fd21 100644 --- a/tests/generators/kzg_7594/main.py +++ b/tests/generators/kzg_7594/main.py @@ -565,7 +565,6 @@ def cases_fn() -> Iterable[gen_typing.TestCase]: if __name__ == "__main__": bls.use_arkworks() gen_runner.run_generator("kzg_7594", [ - # EIP-7594 create_provider(FULU, 'compute_cells_and_kzg_proofs', case_compute_cells_and_kzg_proofs), create_provider(FULU, 'verify_cell_kzg_proof_batch', case_verify_cell_kzg_proof_batch), create_provider(FULU, 'recover_cells_and_kzg_proofs', case_recover_cells_and_kzg_proofs), From deb5241fd694f8f15f1806166b269527aa9ef771 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 11 Dec 2024 12:12:14 -0600 Subject: [PATCH 127/141] Update table entry for Fulu in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7acc28706..e6ce14ec36 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Features are researched and developed in parallel, and then consolidated into se | Seq. | Code Name | Fork Epoch | Specs | | - | - | - | - | | 5 | **Electra** | TBD |
  • Core
    • [Beacon Chain changes](specs/electra/beacon-chain.md)
    • [Electra fork](specs/electra/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/electra/light-client/sync-protocol.md) ([fork](specs/electra/light-client/fork.md), [networking](specs/electra/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/electra/validator.md)
    • [P2P networking](specs/electra/p2p-interface.md)
| -| 6 | **Fulu** | TBD |
  • Core
    • [Fulu fork](specs/fulu/fork.md)
    • [Data availability sampling core](specs/fulu/das-core.md)
    • [Polynomial commitments sampling](specs/fulu/polynomial-commitments-sampling.md)
    • [Fork choice changes](specs/fulu/fork.md)
  • Additions
    • [P2P networking](specs/fulu/p2p-interface.md)
    • [Peer sampling](specs/fulu/peer-sampling.md)
| +| 6 | **Fulu** | TBD |
  • Core
    • [Beacon Chain changes](specs/fulu/beacon-chain.md)
    • [Fulu fork](specs/fulu/fork.md)
    • [Data availability sampling core](specs/fulu/das-core.md)
    • [Polynomial commitments sampling](specs/fulu/polynomial-commitments-sampling.md)
    • [Fork choice changes](specs/fulu/fork-choice.md)
  • Additions
    • [Honest validator guide changes](specs/fulu/validator.md)
    • [P2P networking](specs/fulu/p2p-interface.md)
    • [Peer sampling](specs/fulu/peer-sampling.md)
| ### Outdated Specifications From c752833e3cdef8327218f2be704567d9ae1557d9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 12 Dec 2024 12:53:40 -0600 Subject: [PATCH 128/141] Remove EIP-7742 from Electra/Fulu --- README.md | 2 +- configs/mainnet.yaml | 3 - configs/minimal.yaml | 3 - pysetup/spec_builders/electra.py | 6 +- specs/_features/eip7732/beacon-chain.md | 1 - specs/electra/beacon-chain.md | 27 +++----- specs/electra/fork-choice.md | 2 - specs/electra/validator.md | 2 - specs/fulu/beacon-chain.md | 2 - specs/fulu/validator.md | 68 ------------------- .../unittests/test_config_invariants.py | 1 - .../fulu/unittests/test_config_invariants.py | 1 - 12 files changed, 11 insertions(+), 107 deletions(-) delete mode 100644 specs/fulu/validator.md diff --git a/README.md b/README.md index e6ce14ec36..21ca42dddb 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Features are researched and developed in parallel, and then consolidated into se | Seq. | Code Name | Fork Epoch | Specs | | - | - | - | - | | 5 | **Electra** | TBD |
  • Core
    • [Beacon Chain changes](specs/electra/beacon-chain.md)
    • [Electra fork](specs/electra/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/electra/light-client/sync-protocol.md) ([fork](specs/electra/light-client/fork.md), [networking](specs/electra/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/electra/validator.md)
    • [P2P networking](specs/electra/p2p-interface.md)
| -| 6 | **Fulu** | TBD |
  • Core
    • [Beacon Chain changes](specs/fulu/beacon-chain.md)
    • [Fulu fork](specs/fulu/fork.md)
    • [Data availability sampling core](specs/fulu/das-core.md)
    • [Polynomial commitments sampling](specs/fulu/polynomial-commitments-sampling.md)
    • [Fork choice changes](specs/fulu/fork-choice.md)
  • Additions
    • [Honest validator guide changes](specs/fulu/validator.md)
    • [P2P networking](specs/fulu/p2p-interface.md)
    • [Peer sampling](specs/fulu/peer-sampling.md)
| +| 6 | **Fulu** | TBD |
  • Core
    • [Beacon Chain changes](specs/fulu/beacon-chain.md)
    • [Fulu fork](specs/fulu/fork.md)
    • [Data availability sampling core](specs/fulu/das-core.md)
    • [Polynomial commitments sampling](specs/fulu/polynomial-commitments-sampling.md)
    • [Fork choice changes](specs/fulu/fork-choice.md)
  • Additions
    • [P2P networking](specs/fulu/p2p-interface.md)
    • [Peer sampling](specs/fulu/peer-sampling.md)
| ### Outdated Specifications diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index dadb261b44..deb3dcf5fe 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -160,8 +160,6 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 # `9` BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 -# `uint64(6)` -TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 # `uint64(9)` MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA @@ -174,7 +172,6 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -TARGET_BLOBS_PER_BLOCK_FULU: 9 MAX_BLOBS_PER_BLOCK_FULU: 12 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index afb99949a4..460474ebf7 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -161,8 +161,6 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 # `9` BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 9 -# `uint64(6)` -TARGET_BLOBS_PER_BLOCK_ELECTRA: 6 # `uint64(9)` MAX_BLOBS_PER_BLOCK_ELECTRA: 9 # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA @@ -175,7 +173,6 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128 MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 -TARGET_BLOBS_PER_BLOCK_FULU: 9 MAX_BLOBS_PER_BLOCK_FULU: 12 # `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index 43362e4102..f473dbadc3 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -30,8 +30,7 @@ class NoopExecutionEngine(ExecutionEngine): def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - execution_requests_list: Sequence[bytes], - target_blobs_per_block: uint64) -> bool: + execution_requests_list: Sequence[bytes]) -> bool: return True def notify_forkchoice_updated(self: ExecutionEngine, @@ -48,8 +47,7 @@ def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadRespo def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - execution_requests_list: Sequence[bytes], - target_blobs_per_block: uint64) -> bool: + execution_requests_list: Sequence[bytes]) -> bool: return True def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index bac64274ee..2303e33d40 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -705,7 +705,6 @@ def process_execution_payload(state: BeaconState, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, ) ) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index d40e89e2c5..17ac0cbff0 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -206,7 +206,6 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | Description | | - | - | - | -| `TARGET_BLOBS_PER_BLOCK_ELECTRA` | `uint64(6)` | *[New in Electra:EIP7691]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_ELECTRA` | | `MAX_BLOBS_PER_BLOCK_ELECTRA` | `uint64(9)` | *[New in Electra:EIP7691]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | ### Validator cycle @@ -1014,22 +1013,19 @@ class NewPayloadRequest(object): versioned_hashes: Sequence[VersionedHash] parent_beacon_block_root: Root execution_requests: ExecutionRequests # [New in Electra] - target_blobs_per_block: uint64 # [New in Electra:EIP7742] ``` #### Engine APIs ##### Modified `is_valid_block_hash` -*Note*: The function `is_valid_block_hash` is modified to include the additional -`execution_requests_list` and `target_blobs_per_block` parameters in Electra. +*Note*: The function `is_valid_block_hash` is modified to include the additional `execution_requests_list`. ```python def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - execution_requests_list: Sequence[bytes], - target_blobs_per_block: uint64) -> bool: + execution_requests_list: Sequence[bytes]) -> bool: """ Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly. """ @@ -1038,15 +1034,13 @@ def is_valid_block_hash(self: ExecutionEngine, ##### Modified `notify_new_payload` -*Note*: The function `notify_new_payload` is modified to include the additional -`execution_requests_list` and `target_blobs_per_block` parameters in Electra. +*Note*: The function `notify_new_payload` is modified to include the additional `execution_requests_list`. ```python def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - execution_requests_list: Sequence[bytes], - target_blobs_per_block: uint64) -> bool: + execution_requests_list: Sequence[bytes]) -> bool: """ Return ``True`` if and only if ``execution_payload`` and ``execution_requests_list`` are valid with respect to ``self.execution_state``. @@ -1056,9 +1050,8 @@ def notify_new_payload(self: ExecutionEngine, ##### Modified `verify_and_notify_new_payload` -*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameters -`execution_requests_list` and `target_blobs_per_block` when calling `is_valid_block_hash` and -`notify_new_payload` in Electra. +*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameter +`execution_requests_list` when calling `is_valid_block_hash` and `notify_new_payload` in Electra. ```python def verify_and_notify_new_payload(self: ExecutionEngine, @@ -1069,7 +1062,6 @@ def verify_and_notify_new_payload(self: ExecutionEngine, execution_payload = new_payload_request.execution_payload parent_beacon_block_root = new_payload_request.parent_beacon_block_root execution_requests_list = get_execution_requests_list(new_payload_request.execution_requests) # [New in Electra] - target_blobs_per_block = new_payload_request.target_blobs_per_block # [New in Electra:EIP7742] if b'' in execution_payload.transactions: return False @@ -1078,8 +1070,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, if not self.is_valid_block_hash( execution_payload, parent_beacon_block_root, - execution_requests_list, - target_blobs_per_block): + execution_requests_list): return False if not self.is_valid_versioned_hashes(new_payload_request): @@ -1089,8 +1080,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, if not self.notify_new_payload( execution_payload, parent_beacon_block_root, - execution_requests_list, - target_blobs_per_block): + execution_requests_list): return False return True @@ -1254,7 +1244,6 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, # [New in Electra] - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7691:EIP7742] ) ) # Cache execution payload header diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index 8530239325..8bb03e1d3f 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -33,6 +33,4 @@ class PayloadAttributes(object): suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root - target_blobs_per_block: uint64 # [New in Electra:EIP7742] - max_blobs_per_block: uint64 # [New in Electra:EIP7742] ``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index f8882227c7..2e980d5345 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -176,8 +176,6 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] - max_blobs_per_block=MAX_BLOBS_PER_BLOCK_ELECTRA, # [New in Electra:EIP7742] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, diff --git a/specs/fulu/beacon-chain.md b/specs/fulu/beacon-chain.md index 5dca6580f5..9412eb88c4 100644 --- a/specs/fulu/beacon-chain.md +++ b/specs/fulu/beacon-chain.md @@ -27,7 +27,6 @@ | Name | Value | Description | | - | - | - | -| `TARGET_BLOBS_PER_BLOCK_FULU` | `uint64(9)` | *[New in Fulu:EIP7594]* Target number of blobs in a single block limited by `MAX_BLOBS_PER_BLOCK_FULU` | | `MAX_BLOBS_PER_BLOCK_FULU` | `uint64(12)` | *[New in Fulu:EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | #### Execution payload @@ -54,7 +53,6 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, execution_requests=body.execution_requests, - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] ) ) # Cache execution payload header diff --git a/specs/fulu/validator.md b/specs/fulu/validator.md deleted file mode 100644 index b8781e8ad6..0000000000 --- a/specs/fulu/validator.md +++ /dev/null @@ -1,68 +0,0 @@ -# Fulu -- Honest Validator - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Prerequisites](#prerequisites) -- [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [Execution payload](#execution-payload) - - - - -## Introduction - -This document represents the changes to be made in the code of an "honest validator" to implement Fulu. - -## Prerequisites - -This document is an extension of the [Electra -- Honest Validator](../electra/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 [Fulu](./beacon-chain.md) are requisite for this document and used throughout. -Please see related Beacon Chain doc before continuing and use them as a reference throughout. - -## Block proposal - -### Constructing the `BeaconBlockBody` - -#### Execution payload - -`prepare_execution_payload` is updated from the Electra specs. - -*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. -That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. - -``python -def prepare_execution_payload(state: BeaconState, - safe_block_hash: Hash32, - finalized_block_hash: Hash32, - suggested_fee_recipient: ExecutionAddress, - execution_engine: ExecutionEngine) -> Optional[PayloadId]: - # Verify consistency of the parent hash with respect to the previous execution payload header - parent_hash = state.latest_execution_payload_header.block_hash - - # Set the forkchoice head and initiate the payload build process - withdrawals, _ = get_expected_withdrawals(state) - - 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=withdrawals, - parent_beacon_block_root=hash_tree_root(state.latest_block_header), - target_blobs_per_block=TARGET_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] - max_blobs_per_block=MAX_BLOBS_PER_BLOCK_FULU, # [Modified in Fulu:EIP7594] - ) - 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, - ) -``` \ No newline at end of file diff --git a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py index ab9ac149be..ce4b6684a4 100644 --- a/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/electra/unittests/test_config_invariants.py @@ -19,7 +19,6 @@ def test_processing_pending_partial_withdrawals(spec): @spec_test @single_phase def test_networking(spec): - assert spec.config.TARGET_BLOBS_PER_BLOCK_ELECTRA <= spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA assert spec.config.MAX_BLOBS_PER_BLOCK_ELECTRA <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA == diff --git a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py index 57b40f6e2c..fcf98c7e75 100644 --- a/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/fulu/unittests/test_config_invariants.py @@ -31,7 +31,6 @@ def test_polynomical_commitments_sampling(spec): @spec_test @single_phase def test_networking(spec): - assert spec.config.TARGET_BLOBS_PER_BLOCK_FULU <= spec.config.MAX_BLOBS_PER_BLOCK_FULU assert spec.config.MAX_BLOBS_PER_BLOCK_FULU <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK assert ( spec.config.MAX_REQUEST_BLOB_SIDECARS_FULU == From 8f54f87ca5668e4519a74937511a93d40c0dede5 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 12 Dec 2024 17:17:37 -0600 Subject: [PATCH 129/141] Remove unnecessary Electra fork-choice file --- specs/electra/fork-choice.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 specs/electra/fork-choice.md diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md deleted file mode 100644 index 8bb03e1d3f..0000000000 --- a/specs/electra/fork-choice.md +++ /dev/null @@ -1,36 +0,0 @@ -# Electra -- Fork Choice - -## Table of contents - - - - -- [Introduction](#introduction) -- [Containers](#containers) -- [Helpers](#helpers) - - [Extended `PayloadAttributes`](#extended-payloadattributes) - - - - -## Introduction - -This is the modification of the fork choice accompanying the Electra upgrade. - -## Containers - -## Helpers - -### Extended `PayloadAttributes` - -*Note*: `PayloadAttributes` is extended with the target/maximum number of blobs per block. - -```python -@dataclass -class PayloadAttributes(object): - timestamp: uint64 - prev_randao: Bytes32 - suggested_fee_recipient: ExecutionAddress - withdrawals: Sequence[Withdrawal] - parent_beacon_block_root: Root -``` From 98cf01d22dbb1ce2deada5dd11a5d029e54cf6a4 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 13 Dec 2024 13:30:23 -0600 Subject: [PATCH 130/141] Refactor the main Makefile (#3988) --- .circleci/config.yml | 70 ++-- .github/workflows/docs.yml | 2 +- .github/workflows/generate_vectors.yml | 11 +- .github/workflows/run-tests.yml | 55 +-- .gitignore | 1 + Makefile | 449 ++++++++++++++----------- README.md | 3 +- docker/Dockerfile | 5 +- docker/README.md | 2 +- scripts/build_run_docker_tests.sh | 6 +- setup.py | 2 +- tests/README.md | 56 +-- tests/core/pyspec/README.md | 75 +---- tests/generators/README.md | 33 +- 14 files changed, 331 insertions(+), 439 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 80d44bef37..1de55179d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,19 +35,19 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v25-pyspec + venv_name: v30-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v25-pyspec + venv_name: v30-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: checkout_specs: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: # Restore git repo at point close to target branch/revision, to speed up checkout @@ -67,7 +67,7 @@ jobs: - ~/specs-repo install_pyspec_test: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -75,11 +75,11 @@ jobs: - restore_pyspec_cached_venv - run: name: Install pyspec requirements - command: make install_test + command: make eth2spec - save_pyspec_cached_venv test-phase0: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -87,12 +87,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=phase0 + command: make test fork=phase0 - store_test_results: path: tests/core/pyspec/test-reports test-altair: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -100,12 +100,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=altair + command: make test fork=altair - store_test_results: path: tests/core/pyspec/test-reports test-bellatrix: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -113,12 +113,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=bellatrix + command: make test fork=bellatrix - store_test_results: path: tests/core/pyspec/test-reports test-capella: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -126,12 +126,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=capella + command: make test fork=capella - store_test_results: path: tests/core/pyspec/test-reports test-deneb: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -139,12 +139,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=deneb + command: make test fork=deneb - store_test_results: path: tests/core/pyspec/test-reports test-electra: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -152,12 +152,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=electra + command: make test fork=electra - store_test_results: path: tests/core/pyspec/test-reports test-fulu: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -165,12 +165,12 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=fulu + command: make test fork=fulu - store_test_results: path: tests/core/pyspec/test-reports test-whisk: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -178,41 +178,23 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=whisk + command: make test fork=whisk - store_test_results: path: tests/core/pyspec/test-reports - table_of_contents: - docker: - - image: circleci/node:10.16.3 - working_directory: ~/specs-repo - steps: - - checkout - - run: - name: Check table of contents - command: sudo npm install -g doctoc@2.2.0 && make check_toc - codespell: - docker: - - image: cimg/python:3.12.4 - working_directory: ~/specs-repo - steps: - - checkout - - run: - name: Check codespell - command: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell lint: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - restore_pyspec_cached_venv + - run: + name: Install doctoc + command: sudo npm install -g doctoc@2.2.0 - run: name: Run linter for pyspec command: make lint - - run: - name: Run linter for test generators - command: make lint_generators workflows: version: 2.1 test_spec: @@ -245,8 +227,6 @@ workflows: - test-whisk: requires: - install_pyspec_test - - table_of_contents - - codespell - lint: requires: - install_pyspec_test diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b7bfb3538a..930781e77c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build docs - run: make copy_docs + run: make _copy_docs - uses: actions/setup-python@v4 with: python-version: 3.x diff --git a/.github/workflows/generate_vectors.yml b/.github/workflows/generate_vectors.yml index 1f14ff9158..128d402776 100644 --- a/.github/workflows/generate_vectors.yml +++ b/.github/workflows/generate_vectors.yml @@ -36,19 +36,10 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: Clean up Spec Repository - run: | - cd consensus-specs - make clean - - name: Install dependencies and generate pyspec - run: | - cd consensus-specs - make install_test - make -B pyspec - name: Generate tests run: | cd consensus-specs - make -j 16 generate_tests 2>&1 | tee ../consensustestgen.log + make -j 16 gen_all 2>&1 | tee ../consensustestgen.log cp -r presets/ ../consensus-spec-tests/presets cp -r configs/ ../consensus-spec-tests/configs find . -type d -empty -delete diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 84c5d9cee8..3f10d19668 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,9 +24,9 @@ on: - cron: '0 0 * * *' jobs: - table_of_contents: - runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] - steps: + lint: + runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] + steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js @@ -34,40 +34,15 @@ jobs: with: node-version: '20' cache: '' - - name: Check table of contents - run: npm install -g doctoc@2.2.0 && make check_toc - - codespell: - runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12.4' - cache: '' - - name: Check codespell - run: make codespell - - lint: - runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Setup Rust for dependencies - uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.12.4' cache: '' - - name: Install pyspec requirements - run: make install_test + - name: Install doctoc + run: npm install -g doctoc@2.2.0 - name: Run linter for pyspec run: make lint - - name: Run linter for test generators - run: make lint_generators whitespace: runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] @@ -83,7 +58,7 @@ jobs: pyspec-tests: runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] - needs: [lint,codespell,table_of_contents] + needs: [lint] strategy: matrix: version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "fulu", "whisk"] @@ -97,26 +72,24 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: set TEST_PRESET_TYPE + - name: set preset if: github.event.inputs.test_preset_type != '' run: | echo "spec_test_preset_type=${{ github.event.inputs.test_preset_type || env.TEST_PRESET_TYPE }}" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + - name: set preset if: ${{ (github.event_name == 'push' && github.ref_name != 'master') || github.event_name == 'pull_request' }} run: | - echo "spec_test_preset_type=${{ env.TEST_PRESET_TYPE}}" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + echo "spec_test_preset_type=${{ env.TEST_PRESET_TYPE }}" >> $GITHUB_ENV + - name: set preset if: ${{ github.event_name == 'push' && github.ref_name == 'master' }} run: | echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + - name: set preset if: github.event.schedule=='0 0 * * *' run: | echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV - - name: Install pyspec requirements - run: make install_test - name: test-${{ matrix.version }} - run: make citest fork=${{ matrix.version }} TEST_PRESET_TYPE=${{env.spec_test_preset_type}} + run: make test fork=${{ matrix.version }} preset=${{ env.spec_test_preset_type }} - uses: actions/upload-artifact@v4 if: always() with: @@ -133,10 +106,8 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: Install pyspec requirements - run: make install_test - name: Run generators with --modcheck - run: make generate_tests modcheck=true 2>&1 | tee consensustestgen.log + run: make gen_all modcheck=true 2>&1 | tee consensustestgen.log - name: Check for errors run: | if grep -q "\[ERROR\]" consensustestgen.log; then diff --git a/.gitignore b/.gitignore index 57cd180030..56f84dafd8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ venv .venv /.pytest_cache *.swp +.eth2spec build/ output/ diff --git a/Makefile b/Makefile index 48b1b4fbf6..a3a3e24288 100644 --- a/Makefile +++ b/Makefile @@ -1,134 +1,198 @@ -SPEC_DIR = ./specs -SSZ_DIR = ./ssz -TEST_LIBS_DIR = ./tests/core -TEST_GENERATORS_DIR = ./tests/generators -# The working dir during testing -PY_SPEC_DIR = $(TEST_LIBS_DIR)/pyspec -ETH2SPEC_MODULE_DIR = $(PY_SPEC_DIR)/eth2spec -TEST_REPORT_DIR = $(PY_SPEC_DIR)/test-reports -TEST_VECTOR_DIR = ../consensus-spec-tests/tests -GENERATOR_DIR = ./tests/generators -CONFIGS_DIR = ./configs +all: help + +# A list of executable specifications. +# These must pass a strict linter. +ALL_EXECUTABLE_SPEC_NAMES = \ + phase0 \ + altair \ + bellatrix \ + capella \ + deneb \ + electra \ + fulu \ + whisk \ + eip6800 \ + eip7732 + +# A list of fake targets. +.PHONY: \ + check_toc \ + clean \ + coverage \ + detect_errors \ + eth2spec \ + gen_all \ + gen_list \ + help \ + kzg_setups \ + lint \ + pyspec \ + serve_docs \ + test + +############################################################################### +# Help +############################################################################### + +BOLD = $(shell tput bold) +NORM = $(shell tput sgr0) + +# Print target descriptions. +help: + @echo "make $(BOLD)check_toc$(NORM) -- check table of contents" + @echo "make $(BOLD)clean$(NORM) -- delete all untracked files" + @echo "make $(BOLD)coverage$(NORM) -- run pyspec tests with coverage" + @echo "make $(BOLD)detect_errors$(NORM) -- detect generator errors" + @echo "make $(BOLD)eth2spec$(NORM) -- force rebuild eth2spec package" + @echo "make $(BOLD)gen_$(NORM) -- run a single generator" + @echo "make $(BOLD)gen_all$(NORM) -- run all generators" + @echo "make $(BOLD)gen_list$(NORM) -- list all generator targets" + @echo "make $(BOLD)kzg_setups$(NORM) -- generate trusted setups" + @echo "make $(BOLD)lint$(NORM) -- run the linters" + @echo "make $(BOLD)pyspec$(NORM) -- generate python specifications" + @echo "make $(BOLD)serve_docs$(NORM) -- start a local docs web server" + @echo "make $(BOLD)test$(NORM) -- run pyspec tests" + +############################################################################### +# Virtual Environment +############################################################################### + +VENV = venv +PYTHON_VENV = $(VENV)/bin/python3 +PIP_VENV = $(VENV)/bin/pip3 +CODESPELL_VENV = $(VENV)/bin/codespell + +# Make a virtual environment will all of the necessary dependencies. +$(VENV): requirements_preinstallation.txt + @echo "Creating virtual environment" + @python3 -m venv $(VENV) + @$(PIP_VENV) install -r requirements_preinstallation.txt + +############################################################################### +# Specification +############################################################################### + +TEST_LIBS_DIR = $(CURDIR)/tests/core +PYSPEC_DIR = $(TEST_LIBS_DIR)/pyspec +SITE_PACKAGES := $(wildcard $(VENV)/lib/python*/site-packages) +ETH2SPEC := $(SITE_PACKAGES)/eth2spec + +# Install the eth2spec package. +# The pipe indicates that venv is an order-only prerequisite. +# When restoring venv cache, its timestamp is newer than eth2spec. +$(ETH2SPEC): setup.py | $(VENV) + @$(PIP_VENV) install .[docs,lint,test,generator] + +# Force rebuild/install the eth2spec package. +eth2spec: + $(MAKE) --always-make $(ETH2SPEC) + +# Create the pyspec for all phases. +pyspec: $(VENV) setup.py + @echo "Building all pyspecs" + @$(PYTHON_VENV) setup.py pyspecdev + +############################################################################### +# Testing +############################################################################### + +TEST_REPORT_DIR = $(PYSPEC_DIR)/test-reports + +# Run pyspec tests. +# To run a specific test, append k=, eg: +# make test k=test_verify_kzg_proof +# To run tests for a specific fork, append fork=, eg: +# make test fork=deneb +# To run tests for a specific preset, append preset=, eg: +# make test preset=mainnet +# Or all at the same time, eg: +# make test preset=mainnet fork=deneb k=test_verify_kzg_proof +# To run tests with a specific bls library, append bls=, eg: +# make test bls=arkworks +test: MAYBE_TEST := $(if $(k),-k=$(k)) +test: MAYBE_FORK := $(if $(fork),--fork=$(fork)) +test: PRESET := --preset=$(if $(preset),$(preset),minimal) +test: BLS := --bls-type=$(if $(bls),$(bls),fastest) +test: $(ETH2SPEC) pyspec + @mkdir -p $(TEST_REPORT_DIR) + @$(PYTHON_VENV) -m pytest \ + -n auto \ + $(MAYBE_TEST) \ + $(MAYBE_FORK) \ + $(PRESET) \ + $(BLS) \ + --junitxml=$(TEST_REPORT_DIR)/test_results.xml \ + $(PYSPEC_DIR)/eth2spec + +############################################################################### +# Coverage +############################################################################### + TEST_PRESET_TYPE ?= minimal -# Collect a list of generator names -GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) -# Map this list of generator paths to "gen_{generator name}" entries -GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) -GENERATOR_VENVS = $(patsubst $(GENERATOR_DIR)/%, $(GENERATOR_DIR)/%venv, $(GENERATORS)) -# Documents +COV_HTML_OUT=$(PYSPEC_DIR)/.htmlcov +COV_INDEX_FILE=$(COV_HTML_OUT)/index.html +COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) + +# Run pytest with coverage tracking +_test_with_coverage: MAYBE_TEST := $(if $(k),-k=$(k)) +_test_with_coverage: MAYBE_FORK := $(if $(fork),--fork=$(fork)) +_test_with_coverage: $(ETH2SPEC) pyspec + @$(PYTHON_VENV) -m pytest \ + -n auto \ + $(MAYBE_TEST) \ + $(MAYBE_FORK) \ + --disable-bls \ + $(COVERAGE_SCOPE) \ + --cov-report="html:$(COV_HTML_OUT)" \ + --cov-branch \ + $(PYSPEC_DIR)/eth2spec + +# Run tests with coverage then open the coverage report. +# See `make test` for a list of options. +coverage: _test_with_coverage + @echo "Opening result: $(COV_INDEX_FILE)" + @((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & + +############################################################################### +# Documentation +############################################################################### + DOCS_DIR = ./docs +FORK_CHOICE_DIR = ./fork_choice +SPEC_DIR = ./specs SSZ_DIR = ./ssz SYNC_DIR = ./sync -FORK_CHOICE_DIR = ./fork_choice -# To check generator matching: -#$(info $$GENERATOR_TARGETS is [${GENERATOR_TARGETS}]) +# Copy files to the docs directory. +_copy_docs: + @cp -r $(SPEC_DIR) $(DOCS_DIR) + @cp -r $(SYNC_DIR) $(DOCS_DIR) + @cp -r $(SSZ_DIR) $(DOCS_DIR) + @cp -r $(FORK_CHOICE_DIR) $(DOCS_DIR) + @cp $(CURDIR)/README.md $(DOCS_DIR)/README.md +# Start a local documentation server. +serve_docs: _copy_docs + @mkdocs build + @mkdocs serve + +############################################################################### +# Checks +############################################################################### + +FLAKE8_CONFIG = $(CURDIR)/flake8.ini +MYPY_CONFIG = $(CURDIR)/mypy.ini +PYLINT_CONFIG = $(CURDIR)/pylint.ini + +PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), $(PYSPEC_DIR)/eth2spec/$S) +MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S) +TEST_GENERATORS_DIR = ./tests/generators MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/*/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra fulu whisk eip6800 eip7732 -# The parameters for commands. Use `foreach` to avoid listing specs again. -COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) -PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) -MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S) - -COV_HTML_OUT=.htmlcov -COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT) -COV_INDEX_FILE=$(COV_HTML_OUT_DIR)/index.html - -CURRENT_DIR = ${CURDIR} -GENERATOR_ERROR_LOG_FILE = $(CURRENT_DIR)/$(TEST_VECTOR_DIR)/testgen_error_log.txt - -SCRIPTS_DIR = ${CURRENT_DIR}/scripts - -.PHONY: clean partial_clean all test citest lint generate_tests pyspec install_test open_cov \ - check_toc detect_generator_incomplete detect_generator_error_log - -all: $(PY_SPEC_ALL_TARGETS) - -# deletes everything except the venvs -partial_clean: - rm -rf $(TEST_VECTOR_DIR) - rm -rf $(GENERATOR_VENVS) - rm -rf .pytest_cache - rm -f .coverage - rm -rf $(PY_SPEC_DIR)/.pytest_cache - rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/.pytest_cache - rm -rf $(COV_HTML_OUT_DIR) - rm -rf $(TEST_REPORT_DIR) - rm -rf eth2spec.egg-info dist build - rm -rf build; - @for spec_name in $(ALL_EXECUTABLE_SPEC_NAMES) ; do \ - echo $$spec_name; \ - rm -rf $(ETH2SPEC_MODULE_DIR)/$$spec_name; \ - done - -clean: partial_clean - rm -rf venv - # legacy cleanup. The pyspec venv should be located at the repository root - rm -rf $(PY_SPEC_DIR)/venv - rm -rf $(DEPOSIT_CONTRACT_COMPILER_DIR)/venv - rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/venv - -# The pyspec is rebuilt to enforce the /specs being part of eth2specs source distribution. It could be forgotten otherwise. -dist_build: pyspec - python3 setup.py sdist bdist_wheel - -dist_check: - python3 -m twine check dist/* - -dist_upload: - python3 -m twine upload dist/* - -build_wheel: install_test pyspec - . venv/bin/activate && \ - python3 -m build --no-isolation --outdir ./dist ./ - -# "make generate_tests" to run all generators -generate_tests: $(GENERATOR_TARGETS) - -# "make pyspec" to create the pyspec for all phases. -pyspec: - @python3 -m venv venv; . venv/bin/activate; python3 setup.py pyspecdev - -# check the setup tool requirements -preinstallation: - python3 -m venv venv && \ - . venv/bin/activate && \ - python3 -m pip install -r requirements_preinstallation.txt - -install_test: preinstallation - . venv/bin/activate && \ - python3 -m pip install -e .[lint,test] - -# Testing against `minimal` or `mainnet` config by default -test: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --disable-bls $(COVERAGE_SCOPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec - -# Testing against `minimal` or `mainnet` config by default -find_test: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls $(COVERAGE_SCOPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec - -citest: pyspec - mkdir -p $(TEST_REPORT_DIR); -ifdef fork - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec -else - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec -endif - - -open_cov: - ((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & - # Check all files and error if any ToC were modified. check_toc: $(MARKDOWN_FILES:=.toc) @[ "$$(find . -name '*.md.tmp' -print -quit)" ] && exit 1 || exit 0 @@ -145,86 +209,67 @@ check_toc: $(MARKDOWN_FILES:=.toc) echo "\033[1;34m See $*.tmp\033[0m"; \ fi -codespell: - codespell . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist - -lint: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - flake8 --config $(CURRENT_DIR)/flake8.ini ./eth2spec \ - && python -m pylint --rcfile $(CURRENT_DIR)/pylint.ini $(PYLINT_SCOPE) \ - && python -m mypy --config-file $(CURRENT_DIR)/mypy.ini $(MYPY_SCOPE) - -lint_generators: pyspec - . venv/bin/activate; cd $(TEST_GENERATORS_DIR); \ - flake8 --config $(CURRENT_DIR)/flake8.ini - -# If set to true, it will not run generator tests. -modcheck ?= false - -# Runs a generator, identified by param 1 -define run_generator - # Started! - # Create output directory - # Navigate to the generator - # Create a virtual environment, if it does not exist already - # Activate the venv, this is where dependencies are installed for the generator - # Install all the necessary requirements - # Run the generator. The generator is assumed to have an "main.py" file. - # We output to the tests dir (generator program should accept a "-o " argument. - # `-l minimal general` can be added to the generator call to filter to smaller configs, when testing. - echo "generator $(1) started"; \ - mkdir -p $(TEST_VECTOR_DIR); \ - cd $(GENERATOR_DIR)/$(1); \ - if ! test -d venv; then python3 -m venv venv; fi; \ - . venv/bin/activate; \ - pip3 install ../../../dist/eth2spec-*.whl; \ - pip3 install 'eth2spec[generator]'; \ - python3 main.py -o $(CURRENT_DIR)/$(TEST_VECTOR_DIR) $(if $(filter true,$(modcheck)),--modcheck); \ - echo "generator $(1) finished" -endef - -# The tests dir itself is simply built by creating the directory (recursively creating deeper directories if necessary) -$(TEST_VECTOR_DIR): - $(info creating test output directory, for generators: ${GENERATOR_TARGETS}) - mkdir -p $@ -$(TEST_VECTOR_DIR)/: - $(info ignoring duplicate tests dir) - -gen_kzg_setups: - cd $(SCRIPTS_DIR); \ - if ! test -d venv; then python3 -m venv venv; fi; \ - . venv/bin/activate; \ - pip3 install -r requirements.txt; \ - python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/minimal/trusted_setups; \ - python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/mainnet/trusted_setups - -# For any generator, build it using the run_generator function. -# (creation of output dir is a dependency) -gen_%: build_wheel $(TEST_VECTOR_DIR) - $(call run_generator,$*) - -detect_generator_incomplete: $(TEST_VECTOR_DIR) - find $(TEST_VECTOR_DIR) -name "INCOMPLETE" - -detect_generator_error_log: $(TEST_VECTOR_DIR) - [ -f $(GENERATOR_ERROR_LOG_FILE) ] && echo "[ERROR] $(GENERATOR_ERROR_LOG_FILE) file exists" || echo "[PASSED] error log file does not exist" - - -# For docs reader -install_docs: - python3 -m venv venv; . venv/bin/activate; python3 -m pip install -e .[docs]; - -copy_docs: - cp -r $(SPEC_DIR) $(DOCS_DIR); - cp -r $(SYNC_DIR) $(DOCS_DIR); - cp -r $(SSZ_DIR) $(DOCS_DIR); - cp -r $(FORK_CHOICE_DIR) $(DOCS_DIR); - cp $(CURRENT_DIR)/README.md $(DOCS_DIR)/README.md - -build_docs: copy_docs - . venv/bin/activate; - mkdocs build - -serve_docs: - . venv/bin/activate; - mkdocs serve +# Check for mistakes. +lint: $(ETH2SPEC) pyspec check_toc + @$(CODESPELL_VENV) . --skip "./.git,$(VENV),$(PYSPEC_DIR)/.mypy_cache" -I .codespell-whitelist + @$(PYTHON_VENV) -m flake8 --config $(FLAKE8_CONFIG) $(PYSPEC_DIR)/eth2spec + @$(PYTHON_VENV) -m flake8 --config $(FLAKE8_CONFIG) $(TEST_GENERATORS_DIR) + @$(PYTHON_VENV) -m pylint --rcfile $(PYLINT_CONFIG) $(PYLINT_SCOPE) + @$(PYTHON_VENV) -m mypy --config-file $(MYPY_CONFIG) $(MYPY_SCOPE) + +############################################################################### +# Generators +############################################################################### + +TEST_VECTOR_DIR = $(CURDIR)/../consensus-spec-tests/tests +GENERATOR_DIR = $(CURDIR)/tests/generators +SCRIPTS_DIR = $(CURDIR)/scripts +GENERATOR_ERROR_LOG_FILE = $(TEST_VECTOR_DIR)/testgen_error_log.txt +GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) +GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) + +# List available generators. +gen_list: + @for target in $(shell echo $(GENERATOR_TARGETS) | tr ' ' '\n' | sort -n); do \ + echo $$target; \ + done + +# Run one generator. +# To check modules for a generator, append modcheck=true, eg: +# make gen_genesis modcheck=true +gen_%: MAYBE_MODCHECK := $(if $(filter true,$(modcheck)),--modcheck) +gen_%: $(ETH2SPEC) pyspec + @mkdir -p $(TEST_VECTOR_DIR) + @$(PYTHON_VENV) $(GENERATOR_DIR)/$*/main.py \ + --output $(TEST_VECTOR_DIR) \ + $(MAYBE_MODCHECK) + +# Run all generators then check for errors. +gen_all: $(GENERATOR_TARGETS) detect_errors + +# Detect errors in generators. +detect_errors: $(TEST_VECTOR_DIR) + @find $(TEST_VECTOR_DIR) -name "INCOMPLETE" + @if [ -f $(GENERATOR_ERROR_LOG_FILE) ]; then \ + echo "[ERROR] $(GENERATOR_ERROR_LOG_FILE) file exists"; \ + else \ + echo "[PASSED] error log file does not exist"; \ + fi + +# Generate KZG trusted setups for testing. +kzg_setups: $(ETH2SPEC) + @for preset in minimal mainnet; do \ + $(PYTHON_VENV) $(SCRIPTS_DIR)/gen_kzg_trusted_setups.py \ + --secret=1337 \ + --g1-length=4096 \ + --g2-length=65 \ + --output-dir $(CURDIR)/presets/$$preset/trusted_setups; \ + done + +############################################################################### +# Cleaning +############################################################################### + +# Delete all untracked files. +clean: + @git clean -fdx \ No newline at end of file diff --git a/README.md b/README.md index 21ca42dddb..e58927ac9e 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,7 @@ The consensus-specs repo can be used by running the tests locally or inside a do To run the tests locally: - Clone the repository with `git clone https://github.com/ethereum/consensus-specs.git` - Switch to the directory `cd consensus-specs` -- Install the dependencies with: `make install_test && make preinstallation && make pyspec` -- Run the tests with `make citest` +- Run the tests with `make test` To run the tests inside a docker container: - Switch to the directory with `cd scripts` diff --git a/docker/Dockerfile b/docker/Dockerfile index 8ec384499d..d4b2d3567a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,4 @@ RUN apt update && ${INSTALL_CMD} && ${PIP_UPGRADE_CMD} && rm -rf /var/lib/apt/li COPY . . # Inline installation commands -RUN make install_test && \ - make preinstallation && \ - make pyspec - +RUN make pyspec diff --git a/docker/README.md b/docker/README.md index 44dc2b95e5..4824fc283a 100644 --- a/docker/README.md +++ b/docker/README.md @@ -6,7 +6,7 @@ This dockerfile sets up the dependencies required to run consensus-spec tests. T Handy commands: - `docker run -it $IMAGE_NAME /bin/sh` will give you a shell inside the docker container to manually run any tests -- `docker run $IMAGE_NAME make citest` will run the make citest command inside the docker container +- `docker run $IMAGE_NAME make test` will run the make test command inside the docker container Ideally manual running of docker containers is for advanced users, we recommend the script based approach described below for most users. diff --git a/scripts/build_run_docker_tests.sh b/scripts/build_run_docker_tests.sh index 1716a4774c..24d70b145d 100755 --- a/scripts/build_run_docker_tests.sh +++ b/scripts/build_run_docker_tests.sh @@ -82,16 +82,16 @@ else echo "Image $IMAGE_NAME already exists. Skipping build..." fi -# Equivalent to `make citest with the subsequent flags` +# Equivalent to `make test with the subsequent flags` if [ "$FORK_TO_TEST" == "all" ]; then for fork in "${ALL_EXECUTABLE_SPECS[@]}"; do docker run --name $CONTAINER_NAME $IMAGE_NAME \ - make citest fork=$fork TEST_PRESET_TYPE=$TEST_PRESET_TYPE + make test fork=$fork preset=$TEST_PRESET_TYPE copy_test_results $fork done else docker run --name $CONTAINER_NAME $IMAGE_NAME \ - make citest fork=$FORK_TO_TEST TEST_PRESET_TYPE=$TEST_PRESET_TYPE + make test fork=$FORK_TO_TEST preset=$TEST_PRESET_TYPE copy_test_results $FORK_TO_TEST fi diff --git a/setup.py b/setup.py index 83ae7accb4..0bc90ae787 100644 --- a/setup.py +++ b/setup.py @@ -561,7 +561,7 @@ def run(self): python_requires=">=3.9, <4", extras_require={ "test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"], - "lint": ["flake8==5.0.4", "mypy==0.981", "pylint==3.3.1"], + "lint": ["flake8==5.0.4", "mypy==0.981", "pylint==3.3.1", "codespell<3.0.0,>=2.0.0"], "generator": ["setuptools>=72.0.0", "pytest>4.4", "python-snappy==0.7.3", "filelock", "pathos==0.3.0"], "docs": ["mkdocs==1.4.2", "mkdocs-material==9.1.5", "mdx-truly-sane-lists==1.3", "mkdocs-awesome-pages-plugin==2.8.0"] }, diff --git a/tests/README.md b/tests/README.md index 1ffa17239a..798627577d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -17,48 +17,29 @@ Use an OS that has Python 3.8 or above. For example, Debian 11 (bullseye) ``` 3. Create the specifications and tests: ```sh - make install_test - make pyspec + make ``` To read more about creating the environment, [see here](core/pyspec/README.md). ### Running your first test +Use `make` to run the `test_empty_block_transition` tests against the Altair fork like so: -1. Enter the virtual Python environment: - ```sh - cd ~/consensus-specs - . venv/bin/activate - ``` -2. Run a sanity check test against Altair fork: - ```sh - cd tests/core/pyspec - python -m pytest -k test_empty_block_transition --fork altair eth2spec - ``` -3. The output should be similar to: - ``` - ============================= test session starts ============================== - platform linux -- Python 3.9.2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 - rootdir: /home/qbzzt1/consensus-specs - plugins: cov-2.12.1, forked-1.3.0, xdist-2.3.0 - collected 629 items / 626 deselected / 3 selected - - eth2spec/test/bellatrix/sanity/test_blocks.py . [ 33%] - eth2spec/test/phase0/sanity/test_blocks.py .. [100%] - - =============================== warnings summary =============================== - ../../../venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2 - /home/qbzzt1/consensus-specs/venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2: - DeprecationWarning: The toolz.compatibility module is no longer needed in Python 3 and has - been deprecated. Please import these utilities directly from the standard library. This - module will be removed in a future release. - warnings.warn("The toolz.compatibility module is no longer " - - -- Docs: https://docs.pytest.org/en/stable/warnings.html - ================ 3 passed, 626 deselected, 1 warning in 16.81s ================= - ``` - +``` +$ make test k=test_empty_block_transition fork=altair +Building all pyspecs +... +================================= test session starts ================================== +platform darwin -- Python 3.10.3, pytest-8.3.3, pluggy-1.5.0 +rootdir: /Users/jtraglia/Projects/jtraglia/consensus-specs +plugins: cov-5.0.0, xdist-3.6.1 +20 workers [3 items] +s.. [100%] +=================================== warnings summary =================================== +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +====================== 2 passed, 1 skipped, 42 warnings in 7.97s ======================= +``` ## The "Hello, World" of Consensus Spec Tests @@ -451,10 +432,7 @@ Add this function to the file `consensus-specs/tests/core/pyspec/eth2spec/test/p and run the test against Altair fork: ```sh -cd ~/consensus-specs -. venv/bin/activate -cd tests/core/pyspec -python -m pytest -k almost_after --fork altair eth2spec +make test k=almost_after fork=altair ``` You should see it ran successfully (although you might get a warning, you can ignore it) diff --git a/tests/core/pyspec/README.md b/tests/core/pyspec/README.md index baa1322771..2fdd107fb1 100644 --- a/tests/core/pyspec/README.md +++ b/tests/core/pyspec/README.md @@ -7,29 +7,6 @@ With this executable spec, test-generators can easily create test-vectors for client implementations, and the spec itself can be verified to be consistent and coherent through sanity tests implemented with pytest. -## Dev Install - -First, create a `venv` and install the developer dependencies (`test` and `lint` extras): - -```shell -make install_test -``` - -All the dynamic parts of the spec are built with: - -```shell -(venv) python setup.py pyspecdev -``` - -Unlike the regular install, this outputs spec files to their intended source location, -to enable debuggers to navigate between packages and generated code, without fragile directory linking. - -By default, when installing the `eth2spec` as package in non-develop mode, -the distutils implementation of the `setup` runs `build`, which is extended to run the same `pyspec` work, -but outputs into the standard `./build/lib` output. -This enables the `consensus-specs` repository to be installed like any other python package. - - ## Py-tests These tests are not intended for client-consumption. @@ -38,61 +15,41 @@ However, most of the tests can be run in generator-mode, to output test vectors ### How to run tests -#### Automated - -Run `make test` from the root of the specs repository (after running `make install_test` if have not before). - -Note that the `make` commands run through the build steps: it runs the `build` output, not the local package source files. - -#### Manual - -See `Dev install` for test pre-requisites. - -Tests are built for `pytest`. - -Caveats: -- Working directory must be `./tests/core/pyspec`. The work-directory is important to locate eth2 configuration files. -- Run `pytest` as module. It avoids environment differences, and the behavior is different too: - `pytest` as module adds the current directory to the `sys.path` +To run all tests: +```shell +make test +``` -Full test usage, with explicit configuration for illustration of options usage: +To run all tests under the minimal preset: ```shell -(venv) python -m pytest --preset=minimal eth2spec +make test preset=minimal ``` -Or, to run a specific test file, specify the full path: +Or, to run a specific test function specify `k=`: ```shell -(venv) python -m pytest --preset=minimal ./eth2spec/test/phase0/block_processing/test_process_attestation.py +make test k=test_verify_kzg_proof ``` -Or, to run a specific test function (specify the `eth2spec` module, or the script path if the keyword is ambiguous): +Or, to run a specific test function under a single fork specify `k=`: ```shell -(venv) python -m pytest --preset=minimal -k test_success_multi_proposer_index_iterations eth2spec +make test fork=phase0 ``` -Options: -- `--preset`, to change the preset (compile-time configurables). Defaults to `minimal`, can be set to `mainnet`. - Use `@spec_configured_state_test({config here...}` to override runtime configurables on a per-test basis. -- `--disable-bls`, to disable BLS (only for tests that can run without) -- `--bls-type`, `milagro` or `py_ecc` (default) +Note: these options can be used together, like: -### How to view code coverage report - -Run `make open_cov` from the root of the specs repository after running `make test` to open the html code coverage report. +```shell +make test preset=minimal k=test_verify_kzg_proof fork=deneb +``` -### Advanced +### How to view code coverage report -Building spec files from any markdown sources, to a custom location: -```bash -(venv) python setup.py pyspec --spec-fork=phase0 --md-doc-paths="specs/phase0/beacon-chain.md specs/phase0/fork-choice.md" --out-dir=my_spec_dir -``` +Run `make coverage` to run all tests and open the html code coverage report. ## Contributing Contributions are welcome, but consider implementing your idea as part of the spec itself first. The pyspec is not a replacement. - ## License Same as the spec itself; see [LICENSE](../../../LICENSE) file in the specs repository root. diff --git a/tests/generators/README.md b/tests/generators/README.md index 993c1e3472..270d107ea5 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -39,7 +39,7 @@ Prerequisites: This removes the existing virtual environments (`/tests/generators//venv`) and generated tests (`../consensus-spec-tests/tests`). ```bash -make clean +make clean && rm -rf ../consensus-spec-tests/tests ``` ### Running all test generators @@ -47,7 +47,7 @@ make clean This runs all of the generators. ```bash -make -j 4 generate_tests +make -j 4 gen_all ``` The `-j N` flag makes the generators run in parallel, with `N` being the amount of cores. @@ -63,39 +63,12 @@ make gen_ssz_static ## Developing a generator -Simply open up the generator (not all at once) of choice in your favorite IDE/editor and run: - -```bash -# From the root of the generator directory: -# Create a virtual environment (any venv/.venv/.venvs is git-ignored) -python3 -m venv venv -# Activate the venv, this is where dependencies are installed for the generator -. venv/bin/activate -``` - -Now that you have a virtual environment, write your generator. -It's recommended to extend the base-generator. - -Create a `requirements.txt` in the root of your generator directory: -``` -pytest>=4.4 -../../../[generator] -``` - The config helper and pyspec is optional, but preferred. We encourage generators to derive tests from the spec itself in order to prevent code duplication and outdated tests. Applying configurations to the spec is simple and enables you to create test suites with different contexts. *Note*: Make sure to run `make pyspec` from the root of the specs repository in order to build the pyspec requirement. -Install all the necessary requirements (re-run when you add more): -```bash -pip3 install -r requirements.txt -``` - -Note that you may need `PYTHONPATH` to include the pyspec directory, as with running normal tests, - to run test generators manually. The makefile handles this for you already. - -And write your initial test generator, extending the base generator: +Write your initial test generator, extending the base generator: Write a `main.py` file. The shuffling test generator is a good minimal starting point: From 9c4447bdde7f12dbe033facf0ee7b4d369c24427 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 13 Dec 2024 15:22:05 -0600 Subject: [PATCH 131/141] Pepper in some lru_cache decorators --- setup.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 0bc90ae787..55f1d0e344 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ import copy from collections import OrderedDict import json -from functools import reduce +from functools import lru_cache from pysetup.constants import ( # code names @@ -70,6 +70,7 @@ def installPackage(package: str): from marko.ext.gfm.elements import Table +@lru_cache(maxsize=None) def _get_name_from_heading(heading: Heading) -> Optional[str]: last_child = heading.children[-1] if isinstance(last_child, CodeSpan): @@ -77,15 +78,18 @@ def _get_name_from_heading(heading: Heading) -> Optional[str]: return None +@lru_cache(maxsize=None) def _get_source_from_code_block(block: FencedCode) -> str: return block.children[0].children.strip() +@lru_cache(maxsize=None) def _get_function_name_from_source(source: str) -> str: fn = ast.parse(source).body[0] return fn.name +@lru_cache(maxsize=None) def _get_self_type_from_source(source: str) -> Optional[str]: fn = ast.parse(source).body[0] args = fn.args.args @@ -98,6 +102,7 @@ def _get_self_type_from_source(source: str) -> Optional[str]: return args[0].annotation.id +@lru_cache(maxsize=None) def _get_class_info_from_source(source: str) -> Tuple[str, Optional[str]]: class_def = ast.parse(source).body[0] base = class_def.bases[0] @@ -113,12 +118,14 @@ def _get_class_info_from_source(source: str) -> Tuple[str, Optional[str]]: return class_def.name, parent_class +@lru_cache(maxsize=None) def _is_constant_id(name: str) -> bool: if name[0] not in string.ascii_uppercase + '_': return False return all(map(lambda c: c in string.ascii_uppercase + '_' + string.digits, name[1:])) +@lru_cache(maxsize=None) def _load_kzg_trusted_setups(preset_name): trusted_setups_file_path = str(Path(__file__).parent) + '/presets/' + preset_name + '/trusted_setups/trusted_setup_4096.json' @@ -130,6 +137,7 @@ def _load_kzg_trusted_setups(preset_name): return trusted_setup_G1_monomial, trusted_setup_G1_lagrange, trusted_setup_G2_monomial +@lru_cache(maxsize=None) def _load_curdleproofs_crs(preset_name): """ NOTE: File generated from https://github.com/asn-d6/curdleproofs/blob/8e8bf6d4191fb6a844002f75666fb7009716319b/tests/crs.rs#L53-L67 @@ -153,6 +161,7 @@ def _load_curdleproofs_crs(preset_name): } +@lru_cache(maxsize=None) def _get_eth2_spec_comment(child: LinkRefDef) -> Optional[str]: _, _, title = child._parse_info if not (title[0] == "(" and title[len(title)-1] == ")"): @@ -163,6 +172,7 @@ def _get_eth2_spec_comment(child: LinkRefDef) -> Optional[str]: return title[len(ETH2_SPEC_COMMENT_PREFIX):].strip() +@lru_cache(maxsize=None) def _parse_value(name: str, typed_value: str, type_hint: Optional[str] = None) -> VariableDefinition: comment = None if name in ("ROOT_OF_UNITY_EXTENDED", "ROOTS_OF_UNITY_EXTENDED", "ROOTS_OF_UNITY_REDUCED"): @@ -185,6 +195,11 @@ def _update_constant_vars_with_kzg_setups(constant_vars, preset_name): constant_vars['KZG_SETUP_G2_MONOMIAL'] = VariableDefinition(constant_vars['KZG_SETUP_G2_MONOMIAL'].value, str(kzg_setups[2]), comment, None) +@lru_cache(maxsize=None) +def parse_markdown(content: str): + return gfm.parse(content) + + def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], preset_name=str) -> SpecObject: functions: Dict[str, str] = {} protocols: Dict[str, ProtocolDefinition] = {} @@ -198,7 +213,7 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr custom_types: Dict[str, str] = {} with open(file_name) as source_file: - document = gfm.parse(source_file.read()) + document = parse_markdown(source_file.read()) current_name = None should_skip = False @@ -326,6 +341,7 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr ) +@lru_cache(maxsize=None) def load_preset(preset_files: Sequence[Path]) -> Dict[str, str]: """ Loads the a directory of preset files, merges the result into one preset. @@ -344,6 +360,7 @@ def load_preset(preset_files: Sequence[Path]) -> Dict[str, str]: return parse_config_vars(preset) +@lru_cache(maxsize=None) def load_config(config_path: Path) -> Dict[str, str]: """ Loads the given configuration file. @@ -358,7 +375,7 @@ def build_spec(fork: str, source_files: Sequence[Path], preset_files: Sequence[Path], config_file: Path) -> str: - preset = load_preset(preset_files) + preset = load_preset(tuple(preset_files)) config = load_config(config_file) all_specs = [get_spec(spec, preset, config, preset_name) for spec in source_files] From 702dfc97349f06f497079dccb89142e4ccd39236 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 13 Dec 2024 17:25:18 -0600 Subject: [PATCH 132/141] Use incorrect signature in pending deposit top up test --- .../pending_deposits/test_apply_pending_deposit.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_apply_pending_deposit.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_apply_pending_deposit.py index 0c920d56a3..ccbfbc13a3 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_apply_pending_deposit.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_apply_pending_deposit.py @@ -308,7 +308,15 @@ def test_apply_pending_deposit_top_up__zero_balance(spec, state): def test_apply_pending_deposit_incorrect_sig_top_up(spec, state): validator_index = 0 amount = spec.MIN_ACTIVATION_BALANCE // 4 - pending_deposit = prepare_pending_deposit(spec, validator_index, amount, signed=True) + pending_deposit = prepare_pending_deposit(spec, validator_index, amount, signed=False) + + # ensure the deposit signature is incorrect + assert not spec.is_valid_deposit_signature( + pending_deposit.pubkey, + pending_deposit.withdrawal_credentials, + pending_deposit.amount, + pending_deposit.signature + ) # invalid signatures, in top-ups, are allowed! yield from run_pending_deposit_applying(spec, state, pending_deposit, validator_index) From a58b1f52ddbf1daed66cac210256272694f8bb79 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Sun, 15 Dec 2024 08:37:22 +1000 Subject: [PATCH 133/141] clarify gossip sources wording --- specs/_features/eip7732/p2p-interface.md | 4 ++-- specs/deneb/p2p-interface.md | 2 +- specs/fulu/p2p-interface.md | 2 +- specs/phase0/p2p-interface.md | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/_features/eip7732/p2p-interface.md b/specs/_features/eip7732/p2p-interface.md index df02cc2382..22b0ba7ede 100644 --- a/specs/_features/eip7732/p2p-interface.md +++ b/specs/_features/eip7732/p2p-interface.md @@ -151,7 +151,7 @@ This topic is used to propagate execution payload messages as `SignedExecutionPa The following validations MUST pass before forwarding the `signed_execution_payload_envelope` on the network, assuming the alias `envelope = signed_execution_payload_envelope.message`, `payload = payload_envelope.payload`: -- _[IGNORE]_ The envelope's block root `envelope.block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue payload for processing once the block is retrieved). +- _[IGNORE]_ The envelope's block root `envelope.block_root` has been seen (via gossip or non-gossip sources) (a client MAY queue payload for processing once the block is retrieved). - _[IGNORE]_ The node has not seen another valid `SignedExecutionPayloadEnvelope` for this block root from this builder. Let `block` be the block with `envelope.beacon_block_root`. @@ -171,7 +171,7 @@ The following validations MUST pass before forwarding the `payload_attestation_m - _[IGNORE]_ The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`. - _[REJECT]_ The message's payload status is a valid status, i.e. `data.payload_status < PAYLOAD_INVALID_STATUS`. - _[IGNORE]_ The `payload_attestation_message` is the first valid message received from the validator with index `payload_attestation_message.validate_index`. -- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via both gossip and non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). +- _[IGNORE]_ The message's block `data.beacon_block_root` has been seen (via gossip or non-gossip sources) (a client MAY queue attestation for processing once the block is retrieved. Note a client might want to request payload after). - _[REJECT]_ The message's block `data.beacon_block_root` passes validation. - _[REJECT]_ The message's validator index is within the payload committee in `get_ptc(state, data.slot)`. The `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice. - _[REJECT]_ The message's signature of `payload_attestation_message.signature` is valid with respect to the validator index. diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 5f71bc854a..b3edc9d5bf 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -181,7 +181,7 @@ The following validations MUST pass before forwarding the `blob_sidecar` on the - _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `block_header.slot <= current_slot` (a client MAY queue future sidecars for processing at the appropriate slot). - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `block_header.slot > compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)` - _[REJECT]_ The proposer signature of `blob_sidecar.signed_block_header`, is valid with respect to the `block_header.proposer_index` pubkey. -- _[IGNORE]_ The sidecar's block's parent (defined by `block_header.parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue sidecars for processing once the parent block is retrieved). +- _[IGNORE]_ The sidecar's block's parent (defined by `block_header.parent_root`) has been seen (via gossip or non-gossip sources) (a client MAY queue sidecars for processing once the parent block is retrieved). - _[REJECT]_ The sidecar's block's parent (defined by `block_header.parent_root`) passes validation. - _[REJECT]_ The sidecar is from a higher slot than the sidecar's block's parent (defined by `block_header.parent_root`). - _[REJECT]_ The current finalized_checkpoint is an ancestor of the sidecar's block -- i.e. `get_checkpoint_block(store, block_header.parent_root, store.finalized_checkpoint.epoch) == store.finalized_checkpoint.root`. diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index abebbffecc..26227a7eda 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -195,7 +195,7 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi - _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `block_header.slot <= current_slot` (a client MAY queue future sidecars for processing at the appropriate slot). - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `block_header.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` - _[REJECT]_ The proposer signature of `sidecar.signed_block_header`, is valid with respect to the `block_header.proposer_index` pubkey. -- _[IGNORE]_ The sidecar's block's parent (defined by `block_header.parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue sidecars for processing once the parent block is retrieved). +- _[IGNORE]_ The sidecar's block's parent (defined by `block_header.parent_root`) has been seen (via gossip or non-gossip sources) (a client MAY queue sidecars for processing once the parent block is retrieved). - _[REJECT]_ The sidecar's block's parent (defined by `block_header.parent_root`) passes validation. - _[REJECT]_ The sidecar is from a higher slot than the sidecar's block's parent (defined by `block_header.parent_root`). - _[REJECT]_ The current finalized_checkpoint is an ancestor of the sidecar's block -- i.e. `get_checkpoint_block(store, block_header.parent_root, store.finalized_checkpoint.epoch) == store.finalized_checkpoint.root`. diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 396e4671b8..4f7749a007 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -338,7 +338,7 @@ The following validations MUST pass before forwarding the `signed_beacon_block` - _[IGNORE]_ The block is the first block with valid signature received for the proposer for the slot, `signed_beacon_block.message.slot`. - _[REJECT]_ The proposer signature, `signed_beacon_block.signature`, is valid with respect to the `proposer_index` pubkey. - _[IGNORE]_ The block's parent (defined by `block.parent_root`) has been seen - (via both gossip and non-gossip sources) + (via gossip or non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The block's parent (defined by `block.parent_root`) passes validation. - _[REJECT]_ The block is from a higher slot than its parent. @@ -387,7 +387,7 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_ - _[REJECT]_ The aggregator signature, `signed_aggregate_and_proof.signature`, is valid. - _[REJECT]_ The signature of `aggregate` is valid. - _[IGNORE]_ The block being voted for (`aggregate.data.beacon_block_root`) has been seen - (via both gossip and non-gossip sources) + (via gossip or non-gossip sources) (a client MAY queue aggregates for processing once block is retrieved). - _[REJECT]_ The block being voted for (`aggregate.data.beacon_block_root`) passes validation. - _[REJECT]_ The aggregate attestation's target block is an ancestor of the block named in the LMD vote -- i.e. @@ -462,7 +462,7 @@ The following validations MUST pass before forwarding the `attestation` on the s that has an identical `attestation.data.target.epoch` and participating validator index. - _[REJECT]_ The signature of `attestation` is valid. - _[IGNORE]_ The block being voted for (`attestation.data.beacon_block_root`) has been seen - (via both gossip and non-gossip sources) + (via gossip or non-gossip sources) (a client MAY queue attestations for processing once block is retrieved). - _[REJECT]_ The block being voted for (`attestation.data.beacon_block_root`) passes validation. - _[REJECT]_ The attestation's target block is an ancestor of the block named in the LMD vote -- i.e. From 6c581ca42c7e98fbdee7beed5643a41b874100d2 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:46:20 +0800 Subject: [PATCH 134/141] Fix a few typos (#4055) --- specs/_features/whisk/beacon-chain.md | 2 +- tests/core/pyspec/eth2spec/gen_helpers/README.md | 2 +- tests/formats/fork_choice/README.md | 4 ++-- tests/formats/light_client/sync.md | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index de8051ffeb..3b527900e7 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -54,7 +54,7 @@ This document details the beacon chain additions and changes of to support the W | `WHISK_PROPOSER_TRACKERS_COUNT` | `uint64(2**13)` (= 8,192) | number of proposer trackers | | `WHISK_VALIDATORS_PER_SHUFFLE` | `uint64(2**7 - 4)` (= 124) | number of validators shuffled per shuffle step | | `WHISK_MAX_SHUFFLE_PROOF_SIZE` | `uint64(2**15)` | max size of a shuffle proof | -| `WHISK_MAX_OPENING_PROOF_SIZE` | `uint64(2**10)` | max size of a opening proof | +| `WHISK_MAX_OPENING_PROOF_SIZE` | `uint64(2**10)` | max size of an opening proof | ## Configuration diff --git a/tests/core/pyspec/eth2spec/gen_helpers/README.md b/tests/core/pyspec/eth2spec/gen_helpers/README.md index 8fda6b585e..595b411f70 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/README.md +++ b/tests/core/pyspec/eth2spec/gen_helpers/README.md @@ -26,7 +26,7 @@ Options: ## `gen_from_tests` -This is an util to derive tests from a tests source file. +This is a util to derive tests from a tests source file. This requires the tests to yield test-case-part outputs. These outputs are then written to the test case directory. Yielding data is illegal in normal pytests, so it is only done when in "generator mode". diff --git a/tests/formats/fork_choice/README.md b/tests/formats/fork_choice/README.md index 58709b3fee..37d09f4787 100644 --- a/tests/formats/fork_choice/README.md +++ b/tests/formats/fork_choice/README.md @@ -156,10 +156,10 @@ value that Execution Layer client mock returns in responses to the following Eng The checks to verify the current status of `store`. ```yaml -checks: {: value} -- the assertions. +checks: {: value} -- the assertions. ``` -`` is the field member or property of [`Store`](../../../specs/phase0/fork-choice.md#store) object that maintained by client implementation. The fields include: +`` is the field member or property of [`Store`](../../../specs/phase0/fork-choice.md#store) object that maintained by client implementation. The fields include: ```yaml head: { diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index 1706b4c162..d4c8d3ae99 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -48,7 +48,7 @@ should be executed with the specified parameters: ```yaml { current_slot: int -- integer, decimal - checks: {: value} -- the assertions. + checks: {: value} -- the assertions. } ``` @@ -64,7 +64,7 @@ The function `process_light_client_update(store, update, current_slot, genesis_v update: string -- name of the `*.ssz_snappy` file to load as a `LightClientUpdate` object current_slot: int -- integer, decimal - checks: {: value} -- the assertions. + checks: {: value} -- the assertions. } ``` @@ -79,7 +79,7 @@ The `store` should be upgraded to reflect the new `store_fork_digest`: ```yaml { store_fork_digest: string -- Encoded `ForkDigest`-context of `store` - checks: {: value} -- the assertions. + checks: {: value} -- the assertions. } ``` From 2b710f337c701eaa925a8e88ee824e395379c92a Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 17 Dec 2024 10:33:56 -0700 Subject: [PATCH 135/141] clarify blob count validation on blob subnets --- specs/electra/p2p-interface.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index 0016976e93..8ebec6a8e6 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -14,6 +14,7 @@ - [Global topics](#global-topics) - [`beacon_block`](#beacon_block) - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) + - [`blob_sidecar_{subnet_id}`](#blob_sidecar_subnet_id) - [Attestation subnets](#attestation-subnets) - [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id) - [The Req/Resp domain](#the-reqresp-domain) @@ -77,6 +78,14 @@ The following validations are added: * [REJECT] `len(committee_indices) == 1`, where `committee_indices = get_committee_indices(aggregate)`. * [REJECT] `aggregate.data.index == 0` +###### `blob_sidecar_{subnet_id}` + +*[Modified in Electra:EIP7691]* + +The existing validations all apply as given from previous forks, with the following exceptions: + +* Uses of `MAX_BLOBS_PER_BLOCK` in existing validations are replaced with `MAX_BLOBS_PER_BLOCK_ELECTRA`. + ##### Attestation subnets ###### `beacon_attestation_{subnet_id}` From 0964db294c718b0d3574945a963cd2502a1aef32 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Wed, 18 Dec 2024 17:28:51 +1100 Subject: [PATCH 136/141] Fix custody `sampling_size` logic. --- specs/fulu/das-core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/fulu/das-core.md b/specs/fulu/das-core.md index 25576bc1f4..6908144799 100644 --- a/specs/fulu/das-core.md +++ b/specs/fulu/das-core.md @@ -237,7 +237,7 @@ The particular columns/groups that a node custodies are selected pseudo-randomly ## Custody sampling -At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count)` total custody groups. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. +At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count * (NUMBER_OF_COLUMNS / NUMBER_OF_CUSTODY_GROUPS))` total columns. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. ## Extended data From 7be22acf6ac2b07f15f8b2af16b13e81ce57557f Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:26:16 +0800 Subject: [PATCH 137/141] Remove non commit-pinned blob links --- tests/README.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/README.md b/tests/README.md index 798627577d..dc2e02439d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -54,15 +54,14 @@ To learn how consensus spec tests are written, let's go over the code: This [decorator](https://book.pythontips.com/en/latest/decorators.html) specifies that this test is applicable to all the phases of consensus layer development. These phases are similar to forks (Istanbul, -Berlin, London, etc.) in the execution blockchain. If you are interested, [you can see the definition of -this decorator here](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/context.py#L331-L335). +Berlin, London, etc.) in the execution blockchain. ```python @spec_state_test ``` -[This decorator](https://github.com/qbzzt/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/context.py#L232-L234) specifies -that this test is a state transition test, and that it does not include a transition between different forks. +This decorator specifies that this test is a state transition test, and that it does not include a transition +between different forks. ```python def test_empty_block_transition(spec, state): @@ -162,8 +161,7 @@ find . -name '*.py' -exec grep 'def state_transition_and_sign_block' {} \; -prin ``` And you'll find that the function is defined in -[`eth2spec/test/helpers/state.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/state.py). Looking -in that file, we see that the second function is: +`eth2spec/test/helpers/state.py`. Looking in that file, we see that the second function is: ```python def next_slot(spec, state): @@ -199,8 +197,7 @@ verify this). It is important to make sure that the system rejects invalid input, so our next step is to deal with cases where the protocol is supposed to reject something. To see such a test, look at `test_prev_slot_block_transition` (in the same -file we used previously, -[`~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py)). +file we used previously, `~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`). ```python @with_all_phases @@ -230,8 +227,7 @@ Transition to the new slot, which naturally has a different proposer. ``` Specify that the function `transition_unsigned_block` will cause an assertion error. -You can see this function in -[`~/consensus-specs/tests/core/pyspec/eth2spec/test/helpers/block.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/block.py), +You can see this function in `~/consensus-specs/tests/core/pyspec/eth2spec/test/helpers/block.py`, and one of the tests is that the block must be for this slot: > ```python > assert state.slot == block.slot From 35603f5417f6fa9cdd723fb3a546a59c215384ae Mon Sep 17 00:00:00 2001 From: Manu NALEPA Date: Wed, 18 Dec 2024 13:29:44 +0100 Subject: [PATCH 138/141] Metadata: Replace `csc` by `cgc`. --- specs/fulu/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index abebbffecc..e846cb59fc 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -152,14 +152,14 @@ The `MetaData` stored locally by clients is updated with an additional field to seq_number: uint64 attnets: Bitvector[ATTESTATION_SUBNET_COUNT] syncnets: Bitvector[SYNC_COMMITTEE_SUBNET_COUNT] - custody_subnet_count: uint64 # csc + custody_group_count: uint64 # cgc ) ``` Where - `seq_number`, `attnets`, and `syncnets` have the same meaning defined in the Altair document. -- `custody_subnet_count` represents the node's custody subnet count. Clients MAY reject peers with a value less than `CUSTODY_REQUIREMENT`. +- `custody_group_count` represents the node's custody group count. Clients MAY reject peers with a value less than `CUSTODY_REQUIREMENT`. ### The gossip domain: gossipsub From dde81194d7dc68c839d643cb255fbc6243a696ba Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Wed, 18 Dec 2024 22:06:45 +0700 Subject: [PATCH 139/141] EIP-7594: Fix custody group spec tests --- .../test_compute_columns_for_custody_group.py | 62 ++++++++++ .../networking/test_get_custody_columns.py | 113 ------------------ .../networking/test_get_custody_groups.py | 106 ++++++++++++++++ tests/generators/networking/main.py | 3 +- 4 files changed, 170 insertions(+), 114 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/fulu/networking/test_compute_columns_for_custody_group.py delete mode 100644 tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py create mode 100644 tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_groups.py diff --git a/tests/core/pyspec/eth2spec/test/fulu/networking/test_compute_columns_for_custody_group.py b/tests/core/pyspec/eth2spec/test/fulu/networking/test_compute_columns_for_custody_group.py new file mode 100644 index 0000000000..61752e919a --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/fulu/networking/test_compute_columns_for_custody_group.py @@ -0,0 +1,62 @@ +import random + +from eth2spec.test.context import ( + single_phase, + spec_test, + with_fulu_and_later, +) + + +def _run_compute_columns_for_custody_group(spec, rng, custody_group=None): + if custody_group is None: + custody_group = rng.randint(0, spec.config.NUMBER_OF_CUSTODY_GROUPS - 1) + + result = spec.compute_columns_for_custody_group(custody_group) + yield 'custody_group', 'meta', custody_group + + assert len(result) == len(set(result)) + assert len(result) == spec.config.NUMBER_OF_COLUMNS // spec.config.NUMBER_OF_CUSTODY_GROUPS + assert all(i < spec.config.NUMBER_OF_COLUMNS for i in result) + python_list_result = [int(i) for i in result] + + yield 'result', 'meta', python_list_result + + +@with_fulu_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group__min_custody_group(spec): + rng = random.Random(1111) + yield from _run_compute_columns_for_custody_group(spec, rng, custody_group=0) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group__max_custody_group(spec): + rng = random.Random(1111) + yield from _run_compute_columns_for_custody_group(spec, rng, custody_group=spec.config.NUMBER_OF_CUSTODY_GROUPS - 1) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group__1(spec): + rng = random.Random(1111) + yield from _run_compute_columns_for_custody_group(spec, rng) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group__2(spec): + rng = random.Random(2222) + yield from _run_compute_columns_for_custody_group(spec, rng) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_compute_columns_for_custody_group__3(spec): + rng = random.Random(3333) + yield from _run_compute_columns_for_custody_group(spec, rng) diff --git a/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py b/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py deleted file mode 100644 index d3be42ce16..0000000000 --- a/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_columns.py +++ /dev/null @@ -1,113 +0,0 @@ -import random - -from eth2spec.test.context import ( - single_phase, - spec_test, - with_fulu_and_later, -) - - -def _run_get_custody_columns(spec, rng, node_id=None, custody_group_count=None): - if node_id is None: - node_id = rng.randint(0, 2**256 - 1) - - if custody_group_count is None: - custody_group_count = rng.randint(0, spec.config.NUMBER_OF_CUSTODY_GROUPS) - - columns_per_group = spec.config.NUMBER_OF_COLUMNS // spec.config.NUMBER_OF_CUSTODY_GROUPS - groups = spec.get_custody_groups(node_id, custody_group_count) - yield 'node_id', 'meta', node_id - yield 'custody_group_count', 'meta', int(custody_group_count) - - result = [] - for group in groups: - group_columns = spec.compute_columns_for_custody_group(group) - assert len(group_columns) == columns_per_group - result.extend(group_columns) - - assert len(result) == len(set(result)) - assert len(result) == custody_group_count * columns_per_group - assert all(i < spec.config.NUMBER_OF_COLUMNS for i in result) - python_list_result = [int(i) for i in result] - - yield 'result', 'meta', python_list_result - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__min_node_id_min_custody_group_count(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=0, custody_group_count=0) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__min_node_id_max_custody_group_count(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns( - spec, rng, node_id=0, - custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__max_node_id_min_custody_group_count(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=2**256 - 1, custody_group_count=0) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__max_node_id_max_custody_group_count(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns( - spec, rng, node_id=2**256 - 1, - custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, - ) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__max_node_id_max_custody_group_count_minus_1(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns( - spec, rng, node_id=2**256 - 2, - custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, - ) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__short_node_id(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng, node_id=1048576, custody_group_count=1) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__1(spec): - rng = random.Random(1111) - yield from _run_get_custody_columns(spec, rng) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__2(spec): - rng = random.Random(2222) - yield from _run_get_custody_columns(spec, rng) - - -@with_fulu_and_later -@spec_test -@single_phase -def test_get_custody_columns__3(spec): - rng = random.Random(3333) - yield from _run_get_custody_columns(spec, rng) diff --git a/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_groups.py b/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_groups.py new file mode 100644 index 0000000000..8d33a2b920 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/fulu/networking/test_get_custody_groups.py @@ -0,0 +1,106 @@ +import random + +from eth2spec.test.context import ( + single_phase, + spec_test, + with_fulu_and_later, +) + + +def _run_get_custody_groups(spec, rng, node_id=None, custody_group_count=None): + if node_id is None: + node_id = rng.randint(0, 2**256 - 1) + + if custody_group_count is None: + custody_group_count = rng.randint(0, spec.config.NUMBER_OF_CUSTODY_GROUPS) + + result = spec.get_custody_groups(node_id, custody_group_count) + yield 'node_id', 'meta', node_id + yield 'custody_group_count', 'meta', int(custody_group_count) + + assert len(result) == len(set(result)) + assert len(result) == custody_group_count + assert all(i < spec.config.NUMBER_OF_CUSTODY_GROUPS for i in result) + python_list_result = [int(i) for i in result] + + yield 'result', 'meta', python_list_result + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__min_node_id_min_custody_group_count(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups(spec, rng, node_id=0, custody_group_count=0) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__min_node_id_max_custody_group_count(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups( + spec, rng, node_id=0, + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__max_node_id_min_custody_group_count(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups(spec, rng, node_id=2**256 - 1, custody_group_count=0) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__max_node_id_max_custody_group_count(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups( + spec, rng, node_id=2**256 - 1, + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, + ) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__max_node_id_max_custody_group_count_minus_1(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups( + spec, rng, node_id=2**256 - 2, + custody_group_count=spec.config.NUMBER_OF_CUSTODY_GROUPS, + ) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__short_node_id(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups(spec, rng, node_id=1048576, custody_group_count=1) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__1(spec): + rng = random.Random(1111) + yield from _run_get_custody_groups(spec, rng) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__2(spec): + rng = random.Random(2222) + yield from _run_get_custody_groups(spec, rng) + + +@with_fulu_and_later +@spec_test +@single_phase +def test_get_custody_groups__3(spec): + rng = random.Random(3333) + yield from _run_get_custody_groups(spec, rng) diff --git a/tests/generators/networking/main.py b/tests/generators/networking/main.py index 3217c2cce2..a670f7bd4d 100644 --- a/tests/generators/networking/main.py +++ b/tests/generators/networking/main.py @@ -5,7 +5,8 @@ if __name__ == "__main__": fulu_mods = {key: 'eth2spec.test.fulu.networking.test_' + key for key in [ - 'get_custody_columns', + 'compute_columns_for_custody_group', + 'get_custody_groups', ]} all_mods = { FULU: fulu_mods From c33124ebe40fe2092c138b2c90959330810f539a Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:38:55 -0600 Subject: [PATCH 140/141] Use integer division --- specs/fulu/das-core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/fulu/das-core.md b/specs/fulu/das-core.md index 6908144799..923cb7db29 100644 --- a/specs/fulu/das-core.md +++ b/specs/fulu/das-core.md @@ -237,7 +237,7 @@ The particular columns/groups that a node custodies are selected pseudo-randomly ## Custody sampling -At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count * (NUMBER_OF_COLUMNS / NUMBER_OF_CUSTODY_GROUPS))` total columns. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. +At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count * (NUMBER_OF_COLUMNS // NUMBER_OF_CUSTODY_GROUPS))` total columns. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. ## Extended data From 8e0d0d48e81d6c7c5a8253ab61340f5ea5bac66a Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 19 Dec 2024 09:29:58 +1100 Subject: [PATCH 141/141] Simplify inline code Co-authored-by: Justin Traglia <95511699+jtraglia@users.noreply.github.com> --- specs/fulu/das-core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/fulu/das-core.md b/specs/fulu/das-core.md index 923cb7db29..31c4af3c38 100644 --- a/specs/fulu/das-core.md +++ b/specs/fulu/das-core.md @@ -237,7 +237,7 @@ The particular columns/groups that a node custodies are selected pseudo-randomly ## Custody sampling -At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count * (NUMBER_OF_COLUMNS // NUMBER_OF_CUSTODY_GROUPS))` total columns. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. +At each slot, a node advertising `custody_group_count` downloads a minimum of `sampling_size = max(SAMPLES_PER_SLOT, custody_group_count * columns_per_group)` total columns, where `columns_per_group = NUMBER_OF_COLUMNS // NUMBER_OF_CUSTODY_GROUPS`. The corresponding set of columns is selected by `groups = get_custody_groups(node_id, sampling_size)` and `compute_columns_for_custody_group(group) for group in groups`, so that in particular the subset of columns to custody is consistent with the output of `get_custody_groups(node_id, custody_group_count)`. Sampling is considered successful if the node manages to retrieve all selected columns. ## Extended data