From 8ec477333925cb4c31006e7269d9e449d709dcd9 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 10 Mar 2022 06:31:11 +0100 Subject: [PATCH 1/4] EIP-4844: consensus layer changes --- Makefile | 3 +- specs/eip4844/beacon-chain.md | 165 +++++++++++++++++++++ specs/eip4844/fork.md | 43 ++++++ specs/eip4844/p2p-interface.md | 264 +++++++++++++++++++++++++++++++++ specs/eip4844/validator.md | 135 +++++++++++++++++ 5 files changed, 609 insertions(+), 1 deletion(-) create mode 100644 specs/eip4844/beacon-chain.md create mode 100644 specs/eip4844/fork.md create mode 100644 specs/eip4844/p2p-interface.md create mode 100644 specs/eip4844/validator.md diff --git a/Makefile b/Makefile index ec3302e27..7de4cec2a 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,8 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) $(wildcard $(SPEC_DIR)/alta $(wildcard $(SPEC_DIR)/bellatrix/*.md) \ $(wildcard $(SPEC_DIR)/custody/*.md) \ $(wildcard $(SPEC_DIR)/das/*.md) \ - $(wildcard $(SPEC_DIR)/sharding/*.md) + $(wildcard $(SPEC_DIR)/sharding/*.md) \ + $(wildcard $(SPEC_DIR)/eip4844/*.md) COV_HTML_OUT=.htmlcov COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md new file mode 100644 index 000000000..4ac7cf3d1 --- /dev/null +++ b/specs/eip4844/beacon-chain.md @@ -0,0 +1,165 @@ +# EIP-4844 -- The Beacon Chain + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Custom types](#custom-types) +- [Constants](#constants) +- [Preset](#preset) + - [Trusted setup](#trusted-setup) +- [Configuration](#configuration) +- [Containers](#containers) + - [Extended containers](#extended-containers) + - [`BeaconBlockBody`](#beaconblockbody) +- [Helper functions](#helper-functions) + - [Misc](#misc) + - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) + - [`verify_kzgs_against_transactions`](#verify_kzgs_against_transactions) +- [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Block processing](#block-processing) + - [Blob KZGs](#blob-kzgs) +- [Testing](#testing) + + + + +## Introduction + +This upgrade adds transaction execution to the beacon chain as part of Bellatrix upgrade. + +Additionally, this upgrade introduces the following minor changes: +* Penalty parameter updates to their planned maximally punitive values + +## Custom types + +| Name | SSZ equivalent | Description | +| - | - | - | +| `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | +| `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 + +| Name | Value | +| - | - | +| `BLOB_TX_TYPE` | `uint8(0x05)` | +| `FIELD_ELEMENTS_PER_BLOB` | `4096` | +| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | + + +## Preset + +### Trusted setup + +The trusted setup is part of the preset: during testing a `minimal` insecure variant may be used, +but reusing the `mainnet` settings in public networks is a critical security requirement. + +| Name | Value | +| - | - | +| `KZG_SETUP_G2` | `Vector[G2Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | +| `KZG_SETUP_LAGRANGE` | `Vector[BLSCommitment, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | + +## Configuration + + +## Containers + +### Extended containers + +#### `BeaconBlockBody` + +Note: `BeaconBlock` and `SignedBeaconBlock` types are updated indirectly. + +```python +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data # Eth1 data vote + graffiti: Bytes32 # Arbitrary data + # Operations + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + sync_aggregate: SyncAggregate + # Execution + execution_payload: ExecutionPayload + blob_kzgs: List[KZGCommitment, MAX_OBJECT_LIST_SIZE] # [New in EIP-4844] +``` + +## Helper functions + +### Misc + +#### `tx_peek_blob_versioned_hashes` + +This function retrieves the hashes from the `SignedBlobTransaction` as defined in EIP-4844, using SSZ offsets. +Offsets are little-endian `uint32` values, as defined in the [SSZ specification](../../ssz/simple-serialize.md). + +```python +def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedHash]: + assert opaque_tx[0] == BLOB_TX_TYPE + message_offset = 1 + uint32.decode_bytes(opaque_tx[1:5]) + # field offset: 32 + 8 + 32 + 32 + 8 + 4 + 32 + 4 + 4 = 156 + blob_versioned_hashes_offset = uint32.decode_bytes(opaque_tx[message_offset+156:message_offset+160]) + return [VersionedHash(opaque_tx[x:x+32]) for x in range(blob_versioned_hashes_offset, len(opaque_tx), 32)] +``` + +#### `verify_kzgs_against_transactions` + +```python +def verify_kzgs_against_transactions(transactions: Sequence[Transaction], blob_kzgs: Sequence[KZGCommitment]) -> bool: + all_versioned_hashes = [] + for tx in transactions: + if opaque_tx[0] == BLOB_TX_TYPE: + all_versioned_hashes.extend(tx_peek_blob_versioned_hashes(tx)) + return all_versioned_hashes == [ + kzg_to_versioned_hash(kzg) for kzg in blob_kzgs + ] +``` + +## Beacon chain state transition function + +### Block processing + +```python +def process_block(state: BeaconState, block: BeaconBlock) -> None: + process_block_header(state, block) + if is_execution_enabled(state, block.body): + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) + process_randao(state, block.body) + process_eth1_data(state, block.body) + process_operations(state, block.body) + process_sync_aggregate(state, block.body.sync_aggregate) + process_blob_kzgs(state, block.body) # [New in EIP-4844] +``` + +#### Blob KZGs + +```python +def process_blob_kzgs(body: BeaconBlockBody): + assert verify_kzgs_against_transactions(body.execution_payload.transactions, body.blob_kzgs) + + # TODO do we want to buffer the kzg commitments in the BeaconState, like in the full sharding design? + # This could make a proof to any particular blob commitment more efficient, + # but the buffer structure is also likely to change with full sharding. +``` + +## Testing + +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. + +The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type +when initializing the first body-root: + +```python +state.latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), +``` + diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md new file mode 100644 index 000000000..ad1b00b79 --- /dev/null +++ b/specs/eip4844/fork.md @@ -0,0 +1,43 @@ +# EIP-4844 -- Fork Logic + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + +- [Introduction](#introduction) +- [Configuration](#configuration) +- [Fork to EIP-4844](#fork-to-eip-4844) + - [Fork trigger](#fork-trigger) + - [Upgrading the state](#upgrading-the-state) + + + +## Introduction + +This document describes the process of EIP-4844 upgrade. + +## Configuration + +Warning: this configuration is not definitive. + +| Name | Value | +| - | - | +| `EIP4844_FORK_VERSION` | `Version('0x03000000')` | +| `EIP4844_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | + +## Fork to EIP-4844 + +### Fork trigger + +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 `EIP4844_FORK_EPOCH`. + +Note that for the pure EIP-4844 networks, we don't apply `upgrade_to_eip4844` since it starts with EIP-4844 version logic. + +### Upgrading the state + +The `eip4844.BeaconState` format is equal to the `bellatrix.BeaconState` format, no upgrade has to be performed. + diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md new file mode 100644 index 000000000..6b3ac9bc9 --- /dev/null +++ b/specs/eip4844/p2p-interface.md @@ -0,0 +1,264 @@ +# EIP-4844 -- Networking + +This document contains the consensus-layer networking specification for EIP-4844. + +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 + + + + + + - [Preset](#preset) + - [Configuration](#configuration) + - [Containers](#containers) + - [`BlobsSidecar`](#blobssidecar) + - [`SignedBlobsSidecar`](#signedblobssidecar) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`blobs_sidecar`](#blobs_sidecar) + - [Transitioning the gossip](#transitioning-the-gossip) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + - [BlobsSidecarsByRange v1](#blobssidecarsbyrange-v1) +- [Design decision rationale](#design-decision-rationale) + - [Why are blobs relayed as a sidecar, separate from beacon blocks?](#why-are-blobs-relayed-as-a-sidecar-separate-from-beacon-blocks) + + + + + +## Preset + +| Name | Value | +| - | - | +| `LIMIT_BLOBS_PER_SIDECAR` | `uint64(2**4)` (= 16) | + +## Configuration + +| Name | Value | Description | +|------------------------------------------|-------------------------------|---------------------------------------------------------------------| +| `MAX_REQUEST_BLOBS_SIDECARS` | `2**10` (= 1024) | Maximum number of blobs sidecars in a single request | +| `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` | `2**13` (= 8192, ~1.2 months) | The minimum epoch range over which a node must serve blobs sidecars | + + + +## Containers + +### `BlobsSidecar` + +```python +class BlobsSidecar(Container): + beacon_block_root: Root + beacon_block_slot: Slot + shard: uint64 # [ Forward compatibility ] + blobs: List[Blob, LIMIT_BLOBS_PER_SIDECAR] +``` + +### `SignedBlobsSidecar` + +```python +class SignedBlobsSidecar(Container): + message: BlobsSidecar + signature: BLSSignature +``` + + +## The gossip domain: gossipsub + +Some gossip meshes are upgraded in the fork of EIP4844 to support upgraded types. + +### 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 specification around the creation, validation, and dissemination of messages has not changed from the Bellatrix document unless explicitly noted here. + +The derivation of the `message-id` remains stable. + +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) | +| `blobs_sidecar` | `SignedBlobsSidecar` (new) | + +Note that the `ForkDigestValue` path segment of the topic separates the old and the new `beacon_block` topics. + +#### Global topics + +EIP4844 changes the type of the global beacon block topic and introduces a new global topic for blobs-sidecars. + +##### `beacon_block` + +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in EIP4844. + +In addition to the gossip validations for this topic from prior specifications, +the following validations MUST pass before forwarding the `signed_beacon_block` on the network. +Alias `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`. +- _[REJECT]_ The KZG commitments of the blobs are all correctly encoded compressed BLS G1 Points. + -- i.e. `all(bls.KeyValidate(commitment) for commitment in block.body.blob_kzgs)` +- _[REJECT]_ The KZG commitments correspond to the versioned hashes in the transactions list. + -- i.e. `verify_kzgs_against_transactions(block.body.execution_payload.transactions, block.body.blob_kzgs)` + +##### `blobs_sidecar` + +This topic is used to propagate data blobs included in any given beacon block. + +The following validations MUST pass before forwarding the `signed_blobs_sidecar` on the network; +Alias `sidecar = signed_blobs_sidecar.message`. +- _[IGNORE]_ the `sidecar.beacon_block_slot` is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. `blobs_sidecar.beacon_block_slot == current_slot`. +- _[REJECT]_ the `sidecar.blobs` are all well formatted, i.e. the `BLSFieldElement` in valid range (`x < BLS_MODULUS`). +- _[REJECT]_ the beacon proposer signature, `signed_blobs_sidecar.signature`, is valid -- i.e. +```python +domain = get_domain(state, DOMAIN_BLOBS_SIDECAR, blobs_sidecar.beacon_block_slot / SLOTS_PER_EPOCH) +signing_root = compute_signing_root(blobs_sidecar, domain) +assert bls.Verify(proposer_pubkey, signing_root, signed_blob_header.signature) +``` + where `proposer_pubkey` is the pubkey of the beacon block proposer of `blobs_sidecar.beacon_block_slot` +- _[IGNORE]_ The sidecar is the first sidecar with valid signature received for the `(proposer_index, sidecar.beacon_block_root)` combination, + where `proposer_index` is the validator index of the beacon block proposer of `blobs_sidecar.beacon_block_slot` + +Note that a sidecar may be propagated before or after the corresponding beacon block. + +Once both sidecar and beacon block are received, `verify_blobs_sidecar` can unlock the data-availability fork-choice dependency. + +### 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 Bellatrix. + +## The Req/Resp domain + +### Messages + +#### BeaconBlocksByRange v2 + +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/2/` + +The EIP-4844 fork-digest is introduced to the `context` enum to specify EIP-4844 beacon 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` | +| `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | + +#### BeaconBlocksByRoot v2 + +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` + +The EIP-4844 fork-digest is introduced to the `context` enum to specify EIP-4844 beacon 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` | +| `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | + +#### BlobsSidecarsByRange v1 + +**Protocol ID:** `/eth2/beacon_chain/req/blobs_sidecars_by_range/1/` + +Request Content: +``` +( + start_slot: Slot + count: uint64 + shard: uint64 +) +``` + +Response Content: +``` +( + List[BlobsSidecar, MAX_REQUEST_BLOBS_SIDECARS] +) +``` + +Requests blobs sidecars in the slot range `[start_slot, start_slot + count)`, +leading up to the current head block as selected by fork choice. + +The request and response format is forward-compatible with sharded sidecar sync, but MUST enforce `shard == 0` for now. + +The response is unsigned, i.e. `BlobsSidecarsByRange`, as the signature of the beacon block proposer +may not be available beyond the initial distribution via gossip. + +Before consuming the next response chunk, the response reader SHOULD verify the blobs sidecar is well-formatted and +correct w.r.t. the expected KZG commitments through `verify_blobs_sidecar`. + +`BlobsSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip. + +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 `SignedBlobsSidecar` payload. + +Clients MUST keep a record of signed blobs sidecars seen on the epoch range +`[max(GENESIS_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS), current_epoch]` +where `current_epoch` is defined by the current wall-clock time, +and clients MUST support serving requests of blocks on this range. + +Peers that are unable to reply to block requests within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` +epoch range SHOULD respond with error code `3: ResourceUnavailable`. +Such peers that are unable to successfully reply to this range of requests MAY get descored +or disconnected at any time. + +*Note*: The above requirement implies that nodes that start from a recent weak subjectivity checkpoint +MUST backfill the local blobs database to at least epoch `current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` +to be fully compliant with `BlobsSidecarsByRange` requests. To safely perform such a +backfill of blocks to the recent state, the node MUST validate both (1) the +proposer signatures and (2) that the blocks form a valid chain up to the most +recent block referenced in the weak subjectivity state. + +*Note*: Although clients that bootstrap from a weak subjectivity checkpoint can begin +participating in the networking immediately, other peers MAY +disconnect and/or temporarily ban such an un-synced or semi-synced client. + +Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, +and no more than `MAX_REQUEST_BLOBS_SIDECARS` blocks. + +The following blobs sidecars, where they exist, MUST be sent in consecutive order. + +Clients MAY limit the number of blobs sidecars in the response. + +The response MUST contain no more than `count` blobs sidecars. + +Clients MUST respond with blobs sidecars from their view of the current fork choice +-- that is, blobs sidecars as included by blocks from the single chain defined by the current head. +Of note, blocks from slots before the finalization MUST lead to the finalized block reported in the `Status` handshake. + +Clients MUST respond with blobs sidecars that are consistent from a single chain within the context of the request. + +After the initial blobs 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. + + + +# Design decision rationale + +## Why are blobs relayed as a sidecar, separate from beacon blocks? + +This "sidecar" design provides forward compatibility for further data increases by black-boxing `is_data_available()`: +with full sharding `is_data_available()` can be replaced by data-availability-sampling (DAS) +thus avoiding all blobs being downloaded by all beacon nodes on the network. + +Such sharding design may introduce an updated `BlobsSidecar` to identify the shard, +but does not affect the `BeaconBlock` structure. + diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md new file mode 100644 index 000000000..0bdf947ba --- /dev/null +++ b/specs/eip4844/validator.md @@ -0,0 +1,135 @@ +# EIP-4844 -- Honest Validator + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Helpers](#helpers) + - [`is_data_available`](#is_data_available) + - [`verify_blobs_sidecar`](#verify_blobs_sidecar) +- [Beacon chain responsibilities](#beacon-chain-responsibilities) + - [Block proposal](#block-proposal) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [Blob commitments](#blob-commitments) + - [Beacon Block publishing time](#beacon-block-publishing-time) + + + + +## Introduction + +This document represents the changes to be made in the code of an "honest validator" to implement EIP-4844. + +## Prerequisites + +This document is an extension of the [Bellatrix -- Honest Validator](../altair/validator.md) guide. +All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. + +All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of EIP4844](./beacon-chain.md) are requisite for this document and used throughout. +Please see related Beacon Chain doc before continuing and use them as a reference throughout. + +## 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 verify the sidecar with `verify_blobs`. + +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, kzgs: Sequence[KZGCommitment]): + sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) # implementation dependent, raises an exception if not available + verify_blobs_sidecar(slot, beacon_block_root, kzgs, sidecar) +``` + +### `verify_blobs_sidecar` + +```python +def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, + expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar): + assert blobs_sidecar.shard == 0 # always zero, placeholder for future sharding + assert slot == blobs_sidecar.beacon_block_slot + assert beacon_block_root == blobs_sidecar.beacon_block_root + blobs = blobs_sidecar.blobs + assert len(kzgs) == len(blobs) + for kzg, blob in zip(expected_kzgs, blobs): + assert blob_to_kzg(blob) == kzg +``` + + +## Beacon chain responsibilities + +All validator responsibilities remain unchanged other than those noted below. +Namely, the blob handling and the addition of `BlobsSidecar`. + +### Block proposal + +#### Constructing the `BeaconBlockBody` + +##### Blob commitments + +After retrieving the execution payload from the execution engine as specified in Bellatrix, +the blobs are retrieved and processed: + +```python +# execution_payload = xecution_engine.get_payload(payload_id) +# block.body.execution_payload = execution_payload +# ... + +kzgs, blobs = get_blobs(payload_id) + +# Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions +assert verify_kzgs_against_transactions(execution_payload.transactions, kzgs) + +# Optionally sanity-check that the KZG commitments match the blobs (as produced by the execution engine) +assert len(kzgs) == len(blobs) and [blob_to_kzg(blob) == kzg for blob, kzg in zip(blobs, kzgs)] + +# Update the block body +block.body.blob_kzgs = kzgs +``` + +The `blobs` should be held with the block in preparation of publishing. +Without the `blobs`, the published block will effectively be ignored by honest validators. + +Note: This API is *unstable*. `get_blobs` and `get_payload` may be unified. +Implementers may also retrieve blobs individually per transaction. + +### Beacon Block publishing time + +Before publishing a prepared beacon block proposal, the corresponding blobs are packaged into a sidecar object for distribution to the network: + +```python +blobs_sidecar = BlobsSidecar( + beacon_block_root=hash_tree_root(beacon_block) + beacon_block_slot=beacon_block.slot + shard=0, + blobs=blobs, +) +``` + +And then signed: + +```python +domain = get_domain(state, DOMAIN_BLOBS_SIDECAR, blobs_sidecar.beacon_block_slot / SLOTS_PER_EPOCH) +signing_root = compute_signing_root(blobs_sidecar, domain) +signature = bls.Sign(privkey, signing_root) +signed_blobs_sidecar = SignedBlobsSidecar(message=blobs_sidecar, signature=signature) +``` + +This `signed_blobs_sidecar` is then published to the global `blobs_sidecar` topic as soon as the `beacon_block` is published. + +After publishing the sidecar peers on the network may request the sidecar through sync-requests, or a local user may be interested. +The validator MUST hold on to blobs for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` epochs and serve when capable, +to ensure the data-availability of these blobs throughout the network. + +After `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` nodes MAY prune the blobs and/or stop serving them. + From 45e207be4d99247c9b33fb5a44a0bdc038b2d945 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 14 Mar 2022 18:54:54 +0100 Subject: [PATCH 2/4] EIP-4844 consensus-specs review fixes Co-Authored-By: terenc3t Co-Authored-By: djrtwo --- specs/bellatrix/p2p-interface.md | 2 +- specs/eip4844/beacon-chain.md | 43 +++++++++++++++++++++++++------- specs/eip4844/p2p-interface.md | 18 ++++++------- specs/eip4844/validator.md | 7 +++--- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/specs/bellatrix/p2p-interface.md b/specs/bellatrix/p2p-interface.md index 60a9be774..21badce83 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 Bellatrix. +details on how to handle transitioning gossip topics for EIP-4844. ## The Req/Resp domain diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 4ac7cf3d1..1bcab3a98 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -31,10 +31,7 @@ ## Introduction -This upgrade adds transaction execution to the beacon chain as part of Bellatrix upgrade. - -Additionally, this upgrade introduces the following minor changes: -* Penalty parameter updates to their planned maximally punitive values +This upgrade adds blobs to the beacon chain as part of EIP-4844. ## Custom types @@ -53,6 +50,11 @@ Additionally, this upgrade introduces the following minor changes: | `FIELD_ELEMENTS_PER_BLOB` | `4096` | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_BLOBS_SIDECAR` | `DomainType('0x0a000000')` | ## Preset @@ -91,11 +93,36 @@ class BeaconBlockBody(Container): sync_aggregate: SyncAggregate # Execution execution_payload: ExecutionPayload - blob_kzgs: List[KZGCommitment, MAX_OBJECT_LIST_SIZE] # [New in EIP-4844] + blob_kzgs: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] ``` ## Helper functions +### KZG core + +KZG core functions. These are also defined in EIP-4844 execution specs. + +#### `blob_to_kzg` + +```python +def blob_to_kzg(blob: Blob) -> KZGCommitment: + computed_kzg = bls.Z1 + for value, point_kzg in zip(blob, KZG_SETUP_LAGRANGE): + assert value < BLS_MODULUS + computed_kzg = bls.add( + computed_kzg, + bls.multiply(point_kzg, value) + ) + return computed_kzg +``` + +#### `kzg_to_versioned_hash` + +```python +def kzg_to_versioned_hash(kzg: KZGCommitment) -> VersionedHash: + return BLOB_COMMITMENT_VERSION_KZG + hash(kzg)[1:] +``` + ### Misc #### `tx_peek_blob_versioned_hashes` @@ -120,9 +147,7 @@ def verify_kzgs_against_transactions(transactions: Sequence[Transaction], blob_k for tx in transactions: if opaque_tx[0] == BLOB_TX_TYPE: all_versioned_hashes.extend(tx_peek_blob_versioned_hashes(tx)) - return all_versioned_hashes == [ - kzg_to_versioned_hash(kzg) for kzg in blob_kzgs - ] + return all_versioned_hashes == [ksg_to_version_hash(kzg) for kzg in blob_kzgs] ``` ## Beacon chain state transition function @@ -138,7 +163,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) - process_blob_kzgs(state, block.body) # [New in EIP-4844] + process_blob_kzgs(state, block.body) # [New in EIP-4844] ``` #### Blob KZGs diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 6b3ac9bc9..ff2a11e25 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -37,13 +37,13 @@ The specification of these changes continues in the same format as the network s | Name | Value | | - | - | -| `LIMIT_BLOBS_PER_SIDECAR` | `uint64(2**4)` (= 16) | +| `MAX_BLOBS_PER_BLOCK` | `uint64(2**4)` (= 16) | ## Configuration | Name | Value | Description | |------------------------------------------|-------------------------------|---------------------------------------------------------------------| -| `MAX_REQUEST_BLOBS_SIDECARS` | `2**10` (= 1024) | Maximum number of blobs sidecars in a single request | +| `MAX_REQUEST_BLOBS_SIDECARS` | `2**7` (= 128) | Maximum number of blobs sidecars in a single request | | `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` | `2**13` (= 8192, ~1.2 months) | The minimum epoch range over which a node must serve blobs sidecars | @@ -56,8 +56,7 @@ The specification of these changes continues in the same format as the network s class BlobsSidecar(Container): beacon_block_root: Root beacon_block_slot: Slot - shard: uint64 # [ Forward compatibility ] - blobs: List[Blob, LIMIT_BLOBS_PER_SIDECAR] + blobs: List[Blob, MAX_BLOBS_PER_BLOCK] ``` ### `SignedBlobsSidecar` @@ -117,12 +116,12 @@ Alias `sidecar = signed_blobs_sidecar.message`. - _[REJECT]_ the `sidecar.blobs` are all well formatted, i.e. the `BLSFieldElement` in valid range (`x < BLS_MODULUS`). - _[REJECT]_ the beacon proposer signature, `signed_blobs_sidecar.signature`, is valid -- i.e. ```python -domain = get_domain(state, DOMAIN_BLOBS_SIDECAR, blobs_sidecar.beacon_block_slot / SLOTS_PER_EPOCH) +domain = get_domain(state, DOMAIN_BLOBS_SIDECAR, blobs_sidecar.beacon_block_slot // SLOTS_PER_EPOCH) signing_root = compute_signing_root(blobs_sidecar, domain) assert bls.Verify(proposer_pubkey, signing_root, signed_blob_header.signature) ``` where `proposer_pubkey` is the pubkey of the beacon block proposer of `blobs_sidecar.beacon_block_slot` -- _[IGNORE]_ The sidecar is the first sidecar with valid signature received for the `(proposer_index, sidecar.beacon_block_root)` combination, +- _[IGNORE]_ The sidecar is the first sidecar with valid signature received for the `(proposer_index, sidecar.beacon_block_slot)` combination, where `proposer_index` is the validator index of the beacon block proposer of `blobs_sidecar.beacon_block_slot` Note that a sidecar may be propagated before or after the corresponding beacon block. @@ -132,7 +131,7 @@ Once both sidecar and beacon block are received, `verify_blobs_sidecar` can unlo ### 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 Bellatrix. +details on how to handle transitioning gossip topics for this upgrade. ## The Req/Resp domain @@ -181,7 +180,6 @@ Request Content: ( start_slot: Slot count: uint64 - shard: uint64 ) ``` @@ -195,8 +193,6 @@ Response Content: Requests blobs sidecars in the slot range `[start_slot, start_slot + count)`, leading up to the current head block as selected by fork choice. -The request and response format is forward-compatible with sharded sidecar sync, but MUST enforce `shard == 0` for now. - The response is unsigned, i.e. `BlobsSidecarsByRange`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. @@ -232,7 +228,7 @@ participating in the networking immediately, other peers MAY disconnect and/or temporarily ban such an un-synced or semi-synced client. Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, -and no more than `MAX_REQUEST_BLOBS_SIDECARS` blocks. +and no more than `MAX_REQUEST_BLOBS_SIDECARS` sidecars. The following blobs sidecars, where they exist, MUST be sent in consecutive order. diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index 0bdf947ba..2a1c0a24a 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -28,7 +28,7 @@ This document represents the changes to be made in the code of an "honest valida ## Prerequisites -This document is an extension of the [Bellatrix -- Honest Validator](../altair/validator.md) guide. +This document is an extension of the [Bellatrix -- Honest Validator](../bellatrix/validator.md) guide. All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of EIP4844](./beacon-chain.md) are requisite for this document and used throughout. @@ -56,13 +56,12 @@ def is_data_available(slot: Slot, beacon_block_root: Root, kzgs: Sequence[KZGCom ```python def verify_blobs_sidecar(slot: Slot, beacon_block_root: Root, expected_kzgs: Sequence[KZGCommitment], blobs_sidecar: BlobsSidecar): - assert blobs_sidecar.shard == 0 # always zero, placeholder for future sharding assert slot == blobs_sidecar.beacon_block_slot assert beacon_block_root == blobs_sidecar.beacon_block_root blobs = blobs_sidecar.blobs assert len(kzgs) == len(blobs) for kzg, blob in zip(expected_kzgs, blobs): - assert blob_to_kzg(blob) == kzg + assert blob_to_kzg(blob) == kzg ``` @@ -81,7 +80,7 @@ After retrieving the execution payload from the execution engine as specified in the blobs are retrieved and processed: ```python -# execution_payload = xecution_engine.get_payload(payload_id) +# execution_payload = execution_engine.get_payload(payload_id) # block.body.execution_payload = execution_payload # ... From 9b760dfb54cce4dddb6bfcc94d9772475e8675a4 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 14 Mar 2022 19:08:50 +0100 Subject: [PATCH 3/4] eip4844: beacon doc - update TOC --- specs/eip4844/beacon-chain.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 1bcab3a98..9bbe6b3ee 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -11,6 +11,7 @@ - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) + - [Domain types](#domain-types) - [Preset](#preset) - [Trusted setup](#trusted-setup) - [Configuration](#configuration) @@ -18,6 +19,9 @@ - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) - [Helper functions](#helper-functions) + - [KZG core](#kzg-core) + - [`blob_to_kzg`](#blob_to_kzg) + - [`kzg_to_versioned_hash`](#kzg_to_versioned_hash) - [Misc](#misc) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzgs_against_transactions`](#verify_kzgs_against_transactions) From dc5f9dffa02d1c926437b3dfc7f23e9d1be85168 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 14 Mar 2022 21:50:07 +0100 Subject: [PATCH 4/4] eip4844: process_blob_kzgs - move TODO to issue, add missing input argument --- specs/eip4844/beacon-chain.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 9bbe6b3ee..d0de75445 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -173,12 +173,8 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: #### Blob KZGs ```python -def process_blob_kzgs(body: BeaconBlockBody): +def process_blob_kzgs(state: BeaconState, body: BeaconBlockBody): assert verify_kzgs_against_transactions(body.execution_payload.transactions, body.blob_kzgs) - - # TODO do we want to buffer the kzg commitments in the BeaconState, like in the full sharding design? - # This could make a proof to any particular blob commitment more efficient, - # but the buffer structure is also likely to change with full sharding. ``` ## Testing