From 71775c6e877625fe9df550617095898bf1a798f7 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 27 Oct 2022 08:10:32 -0700 Subject: [PATCH 01/13] EIP4844: Remove signed blobs --- specs/eip4844/p2p-interface.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 0563ff7e6..1576fe96f 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -13,7 +13,6 @@ The specification of these changes continues in the same format as the network s - [Configuration](#configuration) - [Containers](#containers) - [`BlobsSidecar`](#blobssidecar) - - [`SignedBlobsSidecar`](#signedblobssidecar) - [`SignedBeaconBlockAndBlobsSidecar`](#signedbeaconblockandblobssidecar) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) @@ -50,14 +49,6 @@ class BlobsSidecar(Container): kzg_aggregated_proof: KZGProof ``` -### `SignedBlobsSidecar` - -```python -class SignedBlobsSidecar(Container): - message: BlobsSidecar - signature: BLSSignature -``` - ### `SignedBeaconBlockAndBlobsSidecar` ```python From c399e11aa717d7501a1b6cebd1ce5d09b558bade Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 27 Oct 2022 21:23:09 +0200 Subject: [PATCH 02/13] Document how to derive fork context for LC gossip For LC gossip, the documentation did not specify what slot number to use for deriving the gossip objects. This missing documentation is now added to document using `attested_header.slot`. --- specs/altair/light-client/p2p-interface.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index 5c2b27b22..f7575cf53 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -71,6 +71,17 @@ 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.slot))`. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------- | ------------------------------------ | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` and later | `altair.LightClientFinalityUpdate` | + ###### `light_client_optimistic_update` This topic is used to propagate the latest `LightClientOptimisticUpdate` to light clients, allowing them to keep track of the latest `optimistic_header`. @@ -88,6 +99,17 @@ 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.slot))`. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------- | ------------------------------------ | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` and later | `altair.LightClientOptimisticUpdate` | + ### The Req/Resp domain #### Messages From 9dc1a17b2d3d1dda34fcc6ea0d56800fdee43f38 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 28 Oct 2022 20:40:21 +0200 Subject: [PATCH 03/13] Update `remerkleable` to 0.1.25 `remerkleable` was updated to address potentially incorrect computation of `hash_tree_root` against default-initialized `Vector` objects. Switching to the fixed version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6db4aa870..79392e7d1 100644 --- a/setup.py +++ b/setup.py @@ -1131,7 +1131,7 @@ setup( "pycryptodome==3.15.0", "py_ecc==6.0.0", "milagro_bls_binding==1.9.0", - "remerkleable==0.1.24", + "remerkleable==0.1.25", RUAMEL_YAML_VERSION, "lru-dict==1.1.8", MARKO_VERSION, From e453bfe018243f380c896cc83b949408f9d43fbf Mon Sep 17 00:00:00 2001 From: Manu NALEPA Date: Sat, 29 Oct 2022 20:15:24 +0200 Subject: [PATCH 04/13] README.md: Fix broken links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3647eee0..4e99bf636 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Join the chat at https://discord.gg/qGpsxSA](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://discord.gg/qGpsxSA) [![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -To learn more about proof-of-stake and sharding, see the [PoS FAQ](https://eth.wiki/en/concepts/proof-of-stake-faqs), [sharding FAQ](https://eth.wiki/sharding/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). +To learn more about proof-of-stake and sharding, see the [PoS documentation](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/), [sharding documentation](https://ethereum.org/en/upgrades/sharding/#main-content) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). This repository hosts the current Ethereum proof-of-stake specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed-upon changes to the spec can be made through pull requests. From 826c20ffc2dad1f38c1112b7a1e48958ac59fe7e Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Tue, 1 Nov 2022 12:54:33 -0500 Subject: [PATCH 05/13] Capella: Add Gossip Topic bls_to_execution_change --- specs/capella/p2p-interface.md | 110 +++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index e69de29bb..11a782fa0 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -0,0 +1,110 @@ +# 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 + + + + + +- [Modifications in Capella](#modifications-in-capella) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`bls_to_execution_change`](#bls_to_execution_change) + - [Transitioning the gossip](#transitioning-the-gossip) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + + + + + +# Modifications in Capella + +## The gossip domain: gossipsub + +A new topic is added to support the gossip of bls to execution change messages. + +### Topics and messages + +Topics follow the same specification as in prior upgrades. All topics remain stable except the beacon block topic which is updated with the modified type. + +The new topics along with the type of the `data` field of a gossipsub message are given in this table: + +| Name | Message Type | +| - | - | +| `beacon_block` | `SignedBeaconBlock` (modified) | +| `bls_to_execution_change` | `SignedBLSToExecutionChange` | + +Note that the `ForkDigestValue` path segment of the topic separates the old and the new `beacon_block` topics. + +#### Global topics + +Capella changes the type of the global beacon block topic and adds one global topic to propagate bls to execution change messages to all potential proposers of beacon blocks. + +##### `beacon_block` + +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in Capella. +Specifically, this type changes with the addition of `bls_to_execution_changes` to the inner `BeaconBlockBody`. +See Capella [state transition document](./beacon-chain.md#beaconblockbody) for further details. + +##### `bls_to_execution_change` + +This topic is used to propagate signed bls to execution change messages to be included in future blocks. + +The following validations MUST pass before forwarding the `signed_bls_to_execution_change` on the network: + +- _[IGNORE]_ The `signed_bls_to_execution_change` is the first valid signed bls to execution change received + for the validator with index `signed_bls_to_execution_change.message.validator_index`. +- _[REJECT]_ All of the conditions within `process_bls_to_execution_change` pass validation. + +### Transitioning the gossip + +See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for +details on how to handle transitioning gossip topics for Capella. + +## The Req/Resp domain + +### Messages + +#### BeaconBlocksByRange v2 + +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/2/` + +The Capella fork-digest is introduced to the `context` enum to specify Capella block type. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +| ------------------------ | -------------------------- | +| `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | +| `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | +| `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | + +#### BeaconBlocksByRoot v2 + +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` + +The Capella fork-digest is introduced to the `context` enum to specify Capella block type. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +| ------------------------ | -------------------------- | +| `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | +| `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | +| `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | + From 8788472679e78dce34fdfa49dd5e0a76d218e379 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 2 Nov 2022 13:26:59 -0600 Subject: [PATCH 06/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e99bf636..aa22e05c5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Join the chat at https://discord.gg/qGpsxSA](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://discord.gg/qGpsxSA) [![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -To learn more about proof-of-stake and sharding, see the [PoS documentation](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/), [sharding documentation](https://ethereum.org/en/upgrades/sharding/#main-content) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). +To learn more about proof-of-stake and sharding, see the [PoS documentation](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/), [sharding documentation](https://ethereum.org/en/upgrades/sharding/) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). This repository hosts the current Ethereum proof-of-stake specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed-upon changes to the spec can be made through pull requests. From 86e15764ad75d9a5a91918af19e9b2714ee25dc1 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 3 Nov 2022 17:01:32 +0200 Subject: [PATCH 07/13] EIP4844: Update cryptography API (#3038) This commit changes the public API of the KZG library to the following high-level API: ``` - verify_kzg_proof() - compute_aggregate_kzg_proof() - verify_aggregate_kzg_proof() - blob_to_kzg_commitment() ``` compared to the previous much more low-level API: ``` - compute_powers() - matrix_lincomb() - lincomb() - bytes_to_bls_field() - evaluate_polynomial_in_evaluation_form() - verify_kzg_proof() - compute_kzg_proof() ``` This means that all the cryptographic logic (including Fiat-Shamir) is now isolated and hidden in the KZG library and the `validator.md` file ends up being significantly simplified, only calling high-level KZG functions. Some additional things that this commit does: - Moves all EIP4844 cryptography into polynomial-commitments.md - Improves the Fiat-Shamir stack by removing the need for SSZ and by introducing simple domain separators Co-authored-by: Kevaundray Wedderburn Co-authored-by: Hsiao-Wei Wang Co-authored-by: Dankrad Feist --- setup.py | 8 +- specs/eip4844/beacon-chain.md | 45 +++- specs/eip4844/polynomial-commitments.md | 209 ++++++++++++++---- specs/eip4844/validator.md | 144 +----------- .../polynomial_commitments/__init__.py | 0 .../test_polynomial_commitments.py | 20 ++ .../unittests/validator/test_validator.py | 16 -- .../pyspec/eth2spec/test/helpers/sharding.py | 10 +- 8 files changed, 247 insertions(+), 205 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py diff --git a/setup.py b/setup.py index 79392e7d1..ec62706aa 100644 --- a/setup.py +++ b/setup.py @@ -232,7 +232,7 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str]) -> if not _is_constant_id(name): # Check for short type declarations - if value.startswith(("uint", "Bytes", "ByteList", "Union", "Vector", "List")): + if value.startswith(("uint", "Bytes", "ByteList", "Union", "Vector", "List", "ByteVector")): custom_types[name] = value continue @@ -590,7 +590,6 @@ class EIP4844SpecBuilder(BellatrixSpecBuilder): return super().imports(preset_name) + f''' from eth2spec.utils import kzg from eth2spec.bellatrix import {preset_name} as bellatrix -from eth2spec.utils.ssz.ssz_impl import serialize as ssz_serialize ''' @@ -617,12 +616,13 @@ KZG_SETUP_LAGRANGE = TESTING_KZG_SETUP_LAGRANGE ROOTS_OF_UNITY = kzg.compute_roots_of_unity(TESTING_FIELD_ELEMENTS_PER_BLOB) -def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> BlobsSidecar: - pass''' +def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> Optional[BlobsSidecar]: + return "TEST"''' @classmethod def hardcoded_custom_type_dep_constants(cls, spec_object) -> str: constants = { + 'BYTES_PER_FIELD_ELEMENT': spec_object.constant_vars['BYTES_PER_FIELD_ELEMENT'].value, 'FIELD_ELEMENTS_PER_BLOB': spec_object.preset_vars['FIELD_ELEMENTS_PER_BLOB'].value, 'MAX_BLOBS_PER_BLOCK': spec_object.preset_vars['MAX_BLOBS_PER_BLOCK'].value, } diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 4cf953593..a5f912472 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -23,6 +23,8 @@ - [`ExecutionPayloadHeader`](#executionpayloadheader) - [Helper functions](#helper-functions) - [Misc](#misc) + - [`validate_blobs_sidecar`](#validate_blobs_sidecar) + - [`is_data_available`](#is_data_available) - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions) @@ -44,9 +46,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | Name | SSZ equivalent | Description | | - | - | - | -| `Blob` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | | | `VersionedHash` | `Bytes32` | | -| `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | ## Constants @@ -55,7 +55,6 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. | Name | Value | | - | - | | `BLOB_TX_TYPE` | `uint8(0x05)` | -| `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` | | `VERSIONED_HASH_VERSION_KZG` | `Bytes1(0x01)` | ### Domain types @@ -150,6 +149,43 @@ class ExecutionPayloadHeader(Container): ### Misc +#### `validate_blobs_sidecar` + +```python +def validate_blobs_sidecar(slot: Slot, + beacon_block_root: Root, + expected_kzg_commitments: Sequence[KZGCommitment], + blobs_sidecar: BlobsSidecar) -> None: + assert slot == blobs_sidecar.beacon_block_slot + assert beacon_block_root == blobs_sidecar.beacon_block_root + blobs = blobs_sidecar.blobs + kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof + assert len(expected_kzg_commitments) == len(blobs) + + assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) +``` + +#### `is_data_available` + +The implementation of `is_data_available` is meant to change with later sharding upgrades. +Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, +and validate the sidecar with `validate_blobs_sidecar`. + +Without the sidecar the block may be processed further optimistically, +but MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. + +```python +def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: + # `retrieve_blobs_sidecar` is implementation dependent, raises an exception if not available. + sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) + if sidecar == "TEST": + return True # For testing; remove once we have a way to inject `BlobsSidecar` into tests + validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar) + + return True +``` + + #### `kzg_commitment_to_versioned_hash` ```python @@ -204,6 +240,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) process_blob_kzg_commitments(state, block.body) # [New in EIP-4844] + + # New in EIP-4844, note: Can sync optimistically without this condition, see note on `is_data_available` + assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) ``` #### Execution payload diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 2b2576346..1ecfe4f36 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -10,6 +10,8 @@ - [Custom types](#custom-types) - [Constants](#constants) - [Preset](#preset) + - [Blob](#blob) + - [Crypto](#crypto) - [Trusted setup](#trusted-setup) - [Helper functions](#helper-functions) - [Bit-reversal permutation](#bit-reversal-permutation) @@ -18,16 +20,22 @@ - [`bit_reversal_permutation`](#bit_reversal_permutation) - [BLS12-381 helpers](#bls12-381-helpers) - [`bytes_to_bls_field`](#bytes_to_bls_field) + - [`blob_to_polynomial`](#blob_to_polynomial) + - [`hash_to_bls_field`](#hash_to_bls_field) - [`bls_modular_inverse`](#bls_modular_inverse) - [`div`](#div) - [`g1_lincomb`](#g1_lincomb) - - [`vector_lincomb`](#vector_lincomb) + - [`poly_lincomb`](#poly_lincomb) + - [`compute_powers`](#compute_powers) + - [Polynomials](#polynomials) + - [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form) - [KZG](#kzg) - [`blob_to_kzg_commitment`](#blob_to_kzg_commitment) - [`verify_kzg_proof`](#verify_kzg_proof) - [`compute_kzg_proof`](#compute_kzg_proof) - - [Polynomials](#polynomials) - - [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form) + - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) + - [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof) + - [`verify_aggregate_kzg_proof`](#verify_aggregate_kzg_proof) @@ -46,16 +54,31 @@ This document specifies basic polynomial operations and KZG polynomial commitmen | `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | | `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | | `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | +| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | a polynomial in evaluation form | +| `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | a basic blob data | ## Constants | Name | Value | Notes | | - | - | - | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | Scalar field modulus of BLS12-381 | -| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | Roots of unity of order FIELD_ELEMENTS_PER_BLOB over the BLS12-381 field | +| `BYTES_PER_FIELD_ELEMENT` | `uint64(32)` | Bytes used to encode a BLS scalar field element | ## Preset +### Blob + +| Name | Value | +| - | - | +| `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` | +| `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` | + +### Crypto + +| Name | Value | Notes | +| - | - | - | +| `ROOTS_OF_UNITY` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | Roots of unity of order FIELD_ELEMENTS_PER_BLOB over the BLS12-381 field | + ### Trusted setup The trusted setup is part of the preset: during testing a `minimal` insecure variant may be used, @@ -91,7 +114,7 @@ def is_power_of_two(value: int) -> bool: ```python def reverse_bits(n: int, order: int) -> int: """ - Reverse the bit order of an integer n + Reverse the bit order of an integer ``n``. """ assert is_power_of_two(order) # Convert n to binary with the same number of bits as "order" - 1, then reverse its bit order @@ -117,9 +140,51 @@ def bit_reversal_permutation(sequence: Sequence[T]) -> Sequence[T]: ```python def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: """ - Convert bytes to a BLS field scalar. The output is not uniform over the BLS field. + Convert 32-byte value to a BLS field scalar. The output is not uniform over the BLS field. """ - return int.from_bytes(b, "little") % BLS_MODULUS + return int.from_bytes(b, ENDIANNESS) % BLS_MODULUS +``` + +#### `blob_to_polynomial` + +```python +def blob_to_polynomial(blob: Blob) -> Polynomial: + """ + Convert a blob to list of BLS field scalars. + """ + polynomial = Polynomial() + for i in range(FIELD_ELEMENTS_PER_BLOB): + value = int.from_bytes(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT], ENDIANNESS) + assert value < BLS_MODULUS + polynomial[i] = value + return polynomial +``` + +#### `hash_to_bls_field` + +```python +def hash_to_bls_field(polys: Sequence[Polynomial], + comms: Sequence[KZGCommitment]) -> BLSFieldElement: + """ + Compute 32-byte hash of serialized polynomials and commitments concatenated. + This hash is then converted to a BLS field element, where the result is not uniform over the BLS field. + Return the BLS field element. + """ + # Append the number of polynomials and the degree of each polynomial as a domain separator + num_polys = int.to_bytes(len(polys), 8, ENDIANNESS) + degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) + data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polys + + # Append each polynomial which is composed by field elements + for poly in polys: + for field_element in poly: + data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) + + # Append serialized G1 points + for commitment in comms: + data += commitment + + return bytes_to_bls_field(hash(data)) ``` #### `bls_modular_inverse` @@ -137,7 +202,9 @@ def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: ```python def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement: - """Divide two field elements: `x` by `y`""" + """ + Divide two field elements: ``x`` by `y``. + """ return (int(x) * int(bls_modular_inverse(y))) % BLS_MODULUS ``` @@ -155,22 +222,65 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElemen return KZGCommitment(bls.G1_to_bytes48(result)) ``` -#### `vector_lincomb` +#### `poly_lincomb` ```python -def vector_lincomb(vectors: Sequence[Sequence[BLSFieldElement]], - scalars: Sequence[BLSFieldElement]) -> Sequence[BLSFieldElement]: +def poly_lincomb(polys: Sequence[Polynomial], + scalars: Sequence[BLSFieldElement]) -> Polynomial: """ - Given a list of ``vectors``, interpret it as a 2D matrix and compute the linear combination - of each column with `scalars`: return the resulting vector. + Given a list of ``polynomials``, interpret it as a 2D matrix and compute the linear combination + of each column with `scalars`: return the resulting polynomials. """ - result = [0] * len(vectors[0]) - for v, s in zip(vectors, scalars): + result = [0] * len(polys[0]) + for v, s in zip(polys, scalars): for i, x in enumerate(v): result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS return [BLSFieldElement(x) for x in result] ``` +#### `compute_powers` + +```python +def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]: + """ + Return ``x`` to power of [0, n-1]. + """ + current_power = 1 + powers = [] + for _ in range(n): + powers.append(BLSFieldElement(current_power)) + current_power = current_power * int(x) % BLS_MODULUS + return powers +``` + +### Polynomials + +#### `evaluate_polynomial_in_evaluation_form` + +```python +def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, + z: BLSFieldElement) -> BLSFieldElement: + """ + Evaluate a polynomial (in evaluation form) at an arbitrary point ``z``. + Uses the barycentric formula: + f(z) = (z**WIDTH - 1) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (z - DOMAIN[i]) + """ + width = len(polynomial) + assert width == FIELD_ELEMENTS_PER_BLOB + inverse_width = bls_modular_inverse(width) + + # Make sure we won't divide by zero during division + assert z not in ROOTS_OF_UNITY + + roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) + + result = 0 + for i in range(width): + result += div(int(polynomial[i]) * int(roots_of_unity_brp[i]), (int(z) - roots_of_unity_brp[i])) + result = result * (pow(z, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS + return result +``` + ### KZG KZG core functions. These are also defined in EIP-4844 execution specs. @@ -179,7 +289,7 @@ KZG core functions. These are also defined in EIP-4844 execution specs. ```python def blob_to_kzg_commitment(blob: Blob) -> KZGCommitment: - return g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), blob) + return g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), blob_to_polynomial(blob)) ``` #### `verify_kzg_proof` @@ -204,16 +314,16 @@ def verify_kzg_proof(polynomial_kzg: KZGCommitment, #### `compute_kzg_proof` ```python -def compute_kzg_proof(polynomial: Sequence[BLSFieldElement], z: BLSFieldElement) -> KZGProof: +def compute_kzg_proof(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: """ Compute KZG proof at point `z` with `polynomial` being in evaluation form + Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z) """ # To avoid SSZ overflow/underflow, convert element into int polynomial = [int(i) for i in polynomial] z = int(z) - # Shift our polynomial first (in evaluation form we can't handle the division remainder) y = evaluate_polynomial_in_evaluation_form(polynomial, z) polynomial_shifted = [(p - int(y)) % BLS_MODULUS for p in polynomial] @@ -226,31 +336,56 @@ def compute_kzg_proof(polynomial: Sequence[BLSFieldElement], z: BLSFieldElement) return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial)) ``` -### Polynomials - -#### `evaluate_polynomial_in_evaluation_form` +#### `compute_aggregated_poly_and_commitment` ```python -def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[BLSFieldElement], - z: BLSFieldElement) -> BLSFieldElement: +def compute_aggregated_poly_and_commitment( + blobs: Sequence[Blob], + kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment, BLSFieldElement]: """ - Evaluate a polynomial (in evaluation form) at an arbitrary point `z` - Uses the barycentric formula: - f(z) = (1 - z**WIDTH) / WIDTH * sum_(i=0)^WIDTH (f(DOMAIN[i]) * DOMAIN[i]) / (z - DOMAIN[i]) + Return (1) the aggregated polynomial, (2) the aggregated KZG commitment, + and (3) the polynomial evaluation random challenge. """ - width = len(polynomial) - assert width == FIELD_ELEMENTS_PER_BLOB - inverse_width = bls_modular_inverse(width) + # Generate random linear combination challenges + r = hash_to_bls_field(blobs, kzg_commitments) + r_powers = compute_powers(r, len(kzg_commitments)) + evaluation_challenge = int(r_powers[-1]) * r % BLS_MODULUS - # Make sure we won't divide by zero during division - assert z not in ROOTS_OF_UNITY + # Create aggregated polynomial in evaluation form + aggregated_poly = Polynomial(poly_lincomb([blob_to_polynomial(blob) for blob in blobs], r_powers)) - roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) + # Compute commitment to aggregated polynomial + aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers)) - result = 0 - for i in range(width): - result += div(int(polynomial[i]) * int(roots_of_unity_brp[i]), (z - roots_of_unity_brp[i])) - result = result * (pow(z, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS - return result + return aggregated_poly, aggregated_poly_commitment, evaluation_challenge ``` +#### `compute_aggregate_kzg_proof` + +```python +def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: + commitments = [blob_to_kzg_commitment(blob) for blob in blobs] + aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( + blobs, + commitments + ) + return compute_kzg_proof(aggregated_poly, evaluation_challenge) +``` + +#### `verify_aggregate_kzg_proof` + +```python +def verify_aggregate_kzg_proof(blobs: Sequence[Blob], + expected_kzg_commitments: Sequence[KZGCommitment], + kzg_aggregated_proof: KZGCommitment) -> bool: + aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( + blobs, + expected_kzg_commitments, + ) + + # Evaluate aggregated polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) + y = evaluate_polynomial_in_evaluation_form(aggregated_poly, evaluation_challenge) + + # Verify aggregated proof + return verify_kzg_proof(aggregated_poly_commitment, evaluation_challenge, y, kzg_aggregated_proof) +``` diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index 0cd420637..d03b1842b 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -10,17 +10,7 @@ - [Introduction](#introduction) - [Prerequisites](#prerequisites) -- [Custom types](#custom-types) -- [Containers](#containers) - - [`BlobsAndCommitments`](#blobsandcommitments) - - [`PolynomialAndCommitment`](#polynomialandcommitment) - [Helpers](#helpers) - - [`is_data_available`](#is_data_available) - - [`hash_to_bls_field`](#hash_to_bls_field) - - [`compute_powers`](#compute_powers) - - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) - - [`validate_blobs_sidecar`](#validate_blobs_sidecar) - - [`compute_proof_from_blobs`](#compute_proof_from_blobs) - [`get_blobs_and_kzg_commitments`](#get_blobs_and_kzg_commitments) - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block and sidecar proposal](#block-and-sidecar-proposal) @@ -45,140 +35,8 @@ All behaviors and definitions defined in this document, and documents it extends All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of EIP4844](./beacon-chain.md) are requisite for this document and used throughout. Please see related Beacon Chain doc before continuing and use them as a reference throughout. -## Custom types - -| Name | SSZ equivalent | Description | -| - | - | - | -| `Polynomial` | `List[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | a polynomial in evaluation form | - -## Containers - -### `BlobsAndCommitments` - -```python -class BlobsAndCommitments(Container): - blobs: List[Blob, MAX_BLOBS_PER_BLOCK] - kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] -``` - -### `PolynomialAndCommitment` - -```python -class PolynomialAndCommitment(Container): - polynomial: Polynomial - kzg_commitment: KZGCommitment -``` - - ## Helpers -### `is_data_available` - -The implementation of `is_data_available` is meant to change with later sharding upgrades. -Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, -and validate the sidecar with `validate_blobs_sidecar`. - -Without the sidecar the block may be processed further optimistically, -but MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. - -```python -def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: - # `retrieve_blobs_sidecar` is implementation dependent, raises an exception if not available. - sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) - validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar) - - return True -``` - -### `hash_to_bls_field` - -```python -def hash_to_bls_field(x: Container) -> BLSFieldElement: - """ - Compute 32-byte hash of serialized container and convert it to BLS field. - The output is not uniform over the BLS field. - """ - return bytes_to_bls_field(hash(ssz_serialize(x))) -``` - -### `compute_powers` -```python -def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]: - """ - Return ``x`` to power of [0, n-1]. - """ - current_power = 1 - powers = [] - for _ in range(n): - powers.append(BLSFieldElement(current_power)) - current_power = current_power * int(x) % BLS_MODULUS - return powers -``` - -### `compute_aggregated_poly_and_commitment` - -```python -def compute_aggregated_poly_and_commitment( - blobs: Sequence[Blob], - kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment]: - """ - Return the aggregated polynomial and aggregated KZG commitment. - """ - # Generate random linear combination challenges - r = hash_to_bls_field(BlobsAndCommitments(blobs=blobs, kzg_commitments=kzg_commitments)) - r_powers = compute_powers(r, len(kzg_commitments)) - - # Create aggregated polynomial in evaluation form - aggregated_poly = Polynomial(vector_lincomb(blobs, r_powers)) - - # Compute commitment to aggregated polynomial - aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers)) - - return aggregated_poly, aggregated_poly_commitment -``` - -### `validate_blobs_sidecar` - -```python -def validate_blobs_sidecar(slot: Slot, - beacon_block_root: Root, - expected_kzg_commitments: Sequence[KZGCommitment], - blobs_sidecar: BlobsSidecar) -> None: - assert slot == blobs_sidecar.beacon_block_slot - assert beacon_block_root == blobs_sidecar.beacon_block_root - blobs = blobs_sidecar.blobs - kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof - assert len(expected_kzg_commitments) == len(blobs) - - aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment( - blobs, - expected_kzg_commitments, - ) - - # Generate challenge `x` and evaluate the aggregated polynomial at `x` - x = hash_to_bls_field( - PolynomialAndCommitment(polynomial=aggregated_poly, kzg_commitment=aggregated_poly_commitment) - ) - # Evaluate aggregated polynomial at `x` (evaluation function checks for div-by-zero) - y = evaluate_polynomial_in_evaluation_form(aggregated_poly, x) - - # Verify aggregated proof - assert verify_kzg_proof(aggregated_poly_commitment, x, y, kzg_aggregated_proof) -``` - -### `compute_proof_from_blobs` - -```python -def compute_proof_from_blobs(blobs: Sequence[Blob]) -> KZGProof: - commitments = [blob_to_kzg_commitment(blob) for blob in blobs] - aggregated_poly, aggregated_poly_commitment = compute_aggregated_poly_and_commitment(blobs, commitments) - x = hash_to_bls_field(PolynomialAndCommitment( - polynomial=aggregated_poly, - kzg_commitment=aggregated_poly_commitment, - )) - return compute_kzg_proof(aggregated_poly, x) -``` - ### `get_blobs_and_kzg_commitments` The interface to retrieve blobs and corresponding kzg commitments. @@ -236,7 +94,7 @@ def get_blobs_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> BlobsSidecar beacon_block_root=hash_tree_root(block), beacon_block_slot=block.slot, blobs=blobs, - kzg_aggregated_proof=compute_proof_from_blobs(blobs), + kzg_aggregated_proof=compute_aggregate_kzg_proof(blobs), ) ``` diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py new file mode 100644 index 000000000..dea6aeb8c --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -0,0 +1,20 @@ +from eth2spec.test.context import ( + spec_state_test, + with_eip4844_and_later, +) +from eth2spec.test.helpers.sharding import ( + get_sample_blob, +) + + +@with_eip4844_and_later +@spec_state_test +def test_verify_kzg_proof(spec, state): + x = 3 + blob = get_sample_blob(spec) + commitment = spec.blob_to_kzg_commitment(blob) + polynomial = spec.blob_to_polynomial(blob) + proof = spec.compute_kzg_proof(polynomial, x) + + y = spec.evaluate_polynomial_in_evaluation_form(polynomial, x) + assert spec.verify_kzg_proof(commitment, x, y, proof) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py index 680a0a9c4..634daca2d 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py @@ -10,25 +10,9 @@ from eth2spec.test.context import ( ) from eth2spec.test.helpers.sharding import ( get_sample_opaque_tx, - get_sample_blob, ) -@with_eip4844_and_later -@spec_state_test -def test_verify_kzg_proof(spec, state): - x = 3 - polynomial = get_sample_blob(spec) - polynomial = [int(i) for i in polynomial] - commitment = spec.blob_to_kzg_commitment(polynomial) - - # Get the proof - proof = spec.compute_kzg_proof(polynomial, x) - - y = spec.evaluate_polynomial_in_evaluation_form(polynomial, x) - assert spec.verify_kzg_proof(commitment, x, y, proof) - - def _run_validate_blobs_sidecar_test(spec, state, blob_count): block = build_empty_block_for_next_slot(spec, state) opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count) diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index 6c90153fc..3ce3215eb 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -53,10 +53,16 @@ def get_sample_blob(spec, rng=None): if rng is None: rng = random.Random(5566) - return spec.Blob([ + values = [ rng.randint(0, spec.BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB) - ]) + ] + + b = bytes() + for v in values: + b += v.to_bytes(32, spec.ENDIANNESS) + + return spec.Blob(b) def get_sample_opaque_tx(spec, blob_count=1, rng=None): From b2d72a18f0727e2071be6f10f4393cab8f4b6f05 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 3 Nov 2022 18:08:37 +0200 Subject: [PATCH 08/13] Fix type error in the inputs to hash_to_bls_field() --- specs/eip4844/polynomial-commitments.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 1ecfe4f36..c90c0d38d 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -346,13 +346,16 @@ def compute_aggregated_poly_and_commitment( Return (1) the aggregated polynomial, (2) the aggregated KZG commitment, and (3) the polynomial evaluation random challenge. """ + # Convert blobs to polynomials + polynomials = [blob_to_polynomial(blob) for blob in blobs] + # Generate random linear combination challenges - r = hash_to_bls_field(blobs, kzg_commitments) + r = hash_to_bls_field(polynomials, kzg_commitments) r_powers = compute_powers(r, len(kzg_commitments)) evaluation_challenge = int(r_powers[-1]) * r % BLS_MODULUS # Create aggregated polynomial in evaluation form - aggregated_poly = Polynomial(poly_lincomb([blob_to_polynomial(blob) for blob in blobs], r_powers)) + aggregated_poly = Polynomial(poly_lincomb(polynomials, r_powers)) # Compute commitment to aggregated polynomial aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers)) From cd5567b735a3faac37ffc3018165bf881c36a41d Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 4 Nov 2022 15:54:30 -0600 Subject: [PATCH 09/13] Update p2p-interface.md --- specs/bellatrix/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/bellatrix/p2p-interface.md b/specs/bellatrix/p2p-interface.md index 02d4ef6c9..4d4044689 100644 --- a/specs/bellatrix/p2p-interface.md +++ b/specs/bellatrix/p2p-interface.md @@ -110,7 +110,7 @@ The following gossip validation from prior specifications MUST NOT be applied if ### Transitioning the gossip See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for -details on how to handle transitioning gossip topics for EIP-4844. +details on how to handle transitioning gossip topics. ## The Req/Resp domain From 1f68c57a7ba5f45f7857d6879758ab9cee948c01 Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:13:07 -0500 Subject: [PATCH 10/13] Update specs/capella/p2p-interface.md Co-authored-by: Alex Stokes --- specs/capella/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index 11a782fa0..6e86b998f 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -30,7 +30,7 @@ The specification of these changes continues in the same format as the network s ## The gossip domain: gossipsub -A new topic is added to support the gossip of bls to execution change messages. +A new topic is added to support the gossip of withdrawal credential change messages. And an existing topic is upgraded for updated types in Capella. ### Topics and messages From 6c1fa0a48561f7564276cd574cb0c14e8317b5ad Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:13:15 -0500 Subject: [PATCH 11/13] Update specs/capella/p2p-interface.md Co-authored-by: Alex Stokes --- specs/capella/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index 6e86b998f..1552991c0 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -34,7 +34,7 @@ A new topic is added to support the gossip of withdrawal credential change messa ### Topics and messages -Topics follow the same specification as in prior upgrades. All topics remain stable except the beacon block topic which is updated with the modified type. +Topics follow the same specification as in prior upgrades. All existing topics remain stable except the beacon block topic which is updated with the modified type. The new topics along with the type of the `data` field of a gossipsub message are given in this table: From 355ca296b8c8c22520572e8896089917fe70f3f7 Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:13:23 -0500 Subject: [PATCH 12/13] Update specs/capella/p2p-interface.md Co-authored-by: Alex Stokes --- specs/capella/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index 1552991c0..4cb23a67e 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -47,7 +47,7 @@ Note that the `ForkDigestValue` path segment of the topic separates the old and #### Global topics -Capella changes the type of the global beacon block topic and adds one global topic to propagate bls to execution change messages to all potential proposers of beacon blocks. +Capella changes the type of the global beacon block topic and adds one global topic to propagate withdrawal credential change messages to all potential proposers of beacon blocks. ##### `beacon_block` From b5ecf44c911f6772ae1f2c2dfa567f07f9d27ec7 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 4 Nov 2022 16:41:07 -0600 Subject: [PATCH 13/13] add note about packing BLS to execution changes into a block --- specs/capella/validator.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/specs/capella/validator.md b/specs/capella/validator.md index 85dbd7e00..90176e035 100644 --- a/specs/capella/validator.md +++ b/specs/capella/validator.md @@ -18,6 +18,7 @@ - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [ExecutionPayload](#executionpayload) + - [BLS to execution changes](#bls-to-execution-changes) @@ -106,3 +107,7 @@ def prepare_execution_payload(state: BeaconState, payload_attributes=payload_attributes, ) ``` + +##### BLS to execution changes + +Up to `MAX_BLS_TO_EXECUTION_CHANGES`, [`BLSToExecutionChange`](./beacon-chain.md#blstoexecutionchange) objects can be included in the `block`. The BLS to execution changes must satisfy the verification conditions found in [BLS to execution change processing](./beacon-chain.md#new-process_bls_to_execution_change).