Merge pull request #2850 from protolambda/eip4844
EIP-4844: consensus-layer specs of Shard Blob Transactions
This commit is contained in:
commit
b8c061cfd7
3
Makefile
3
Makefile
|
@ -27,7 +27,8 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) $(wildcard $(SPEC_DIR)/alta
|
||||||
$(wildcard $(SPEC_DIR)/bellatrix/*.md) \
|
$(wildcard $(SPEC_DIR)/bellatrix/*.md) \
|
||||||
$(wildcard $(SPEC_DIR)/custody/*.md) \
|
$(wildcard $(SPEC_DIR)/custody/*.md) \
|
||||||
$(wildcard $(SPEC_DIR)/das/*.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=.htmlcov
|
||||||
COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT)
|
COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT)
|
||||||
|
|
|
@ -110,7 +110,7 @@ The following gossip validation from prior specifications MUST NOT be applied if
|
||||||
### Transitioning the gossip
|
### Transitioning the gossip
|
||||||
|
|
||||||
See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for
|
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
|
## The Req/Resp domain
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
# EIP-4844 -- The Beacon Chain
|
||||||
|
|
||||||
|
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Custom types](#custom-types)
|
||||||
|
- [Constants](#constants)
|
||||||
|
- [Domain types](#domain-types)
|
||||||
|
- [Preset](#preset)
|
||||||
|
- [Trusted setup](#trusted-setup)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Containers](#containers)
|
||||||
|
- [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)
|
||||||
|
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||||
|
- [Block processing](#block-processing)
|
||||||
|
- [Blob KZGs](#blob-kzgs)
|
||||||
|
- [Testing](#testing)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- /TOC -->
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This upgrade adds blobs to the beacon chain as part of EIP-4844.
|
||||||
|
|
||||||
|
## 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` |
|
||||||
|
|
||||||
|
### Domain types
|
||||||
|
|
||||||
|
| Name | Value |
|
||||||
|
| - | - |
|
||||||
|
| `DOMAIN_BLOBS_SIDECAR` | `DomainType('0x0a000000')` |
|
||||||
|
|
||||||
|
## 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_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`
|
||||||
|
|
||||||
|
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 == [ksg_to_version_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(state: BeaconState, body: BeaconBlockBody):
|
||||||
|
assert verify_kzgs_against_transactions(body.execution_payload.transactions, body.blob_kzgs)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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())),
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# EIP-4844 -- Fork Logic
|
||||||
|
|
||||||
|
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Fork to EIP-4844](#fork-to-eip-4844)
|
||||||
|
- [Fork trigger](#fork-trigger)
|
||||||
|
- [Upgrading the state](#upgrading-the-state)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- /TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
## Preset
|
||||||
|
|
||||||
|
| Name | Value |
|
||||||
|
| - | - |
|
||||||
|
| `MAX_BLOBS_PER_BLOCK` | `uint64(2**4)` (= 16) |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Name | Value | Description |
|
||||||
|
|------------------------------------------|-------------------------------|---------------------------------------------------------------------|
|
||||||
|
| `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 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Containers
|
||||||
|
|
||||||
|
### `BlobsSidecar`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BlobsSidecar(Container):
|
||||||
|
beacon_block_root: Root
|
||||||
|
beacon_block_slot: Slot
|
||||||
|
blobs: List[Blob, MAX_BLOBS_PER_BLOCK]
|
||||||
|
```
|
||||||
|
|
||||||
|
### `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_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.
|
||||||
|
|
||||||
|
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 this upgrade.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
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 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` sidecars.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
# EIP-4844 -- Honest Validator
|
||||||
|
|
||||||
|
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- /TOC -->
|
||||||
|
|
||||||
|
## 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](../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.
|
||||||
|
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 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 = execution_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.
|
||||||
|
|
Loading…
Reference in New Issue