Merge branch 'deneb-4844-clean' into pr3288-comment

This commit is contained in:
Hsiao-Wei Wang 2023-06-07 18:38:20 +08:00
commit 5f241bb7a4
No known key found for this signature in database
GPG Key ID: AE3D6B174F971DE4
29 changed files with 103 additions and 534 deletions

View File

@ -20,5 +20,5 @@ jobs:
with:
key: ${{ github.ref }}
path: .cache
- run: pip install -e .[docs]
- run: pip install mkdocs==1.4.2 mkdocs-material==9.1.5 mdx-truly-sane-lists==1.3 mkdocs-awesome-pages-plugin==2.8.0
- run: mkdocs gh-deploy --force

View File

@ -1101,10 +1101,6 @@ class PySpecCommand(Command):
"""
if self.spec_fork == EIP6110:
self.md_doc_paths += """
specs/_features/eip6110/light-client/fork.md
specs/_features/eip6110/light-client/full-node.md
specs/_features/eip6110/light-client/p2p-interface.md
specs/_features/eip6110/light-client/sync-protocol.md
specs/_features/eip6110/beacon-chain.md
specs/_features/eip6110/fork.md
"""

View File

@ -91,7 +91,8 @@ class ExecutionPayload(Container):
block_hash: Hash32
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
excess_data_gas: uint256
data_gas_used: uint64
excess_data_gas: uint64
deposit_receipts: List[DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD] # [New in EIP6110]
```
@ -116,7 +117,8 @@ class ExecutionPayloadHeader(Container):
block_hash: Hash32
transactions_root: Root
withdrawals_root: Root
excess_data_gas: uint256
data_gas_used: uint64
excess_data_gas: uint64
deposit_receipts_root: Root # [New in EIP6110]
```
@ -268,6 +270,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals),
data_gas_used=payload.data_gas_used,
excess_data_gas=payload.excess_data_gas,
deposit_receipts_root=hash_tree_root(payload.deposit_receipts), # [New in EIP6110]
)

View File

@ -88,7 +88,8 @@ def upgrade_to_eip6110(pre: deneb.BeaconState) -> BeaconState:
block_hash=pre.latest_execution_payload_header.block_hash,
transactions_root=pre.latest_execution_payload_header.transactions_root,
withdrawals_root=pre.latest_execution_payload_header.withdrawals_root,
excess_data_gas=uint256(0),
data_gas_used=uint64(0),
excess_data_gas=uint64(0),
deposit_receipts_root=Root(), # [New in EIP-6110]
)
post = BeaconState(

View File

@ -1,112 +0,0 @@
# EIP-6110 Light Client -- Fork Logic
## 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)
- [Upgrading light client data](#upgrading-light-client-data)
- [Upgrading the store](#upgrading-the-store)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
This document describes how to upgrade existing light client objects based on the [Deneb specification](../../deneb/light-client/sync-protocol.md) to eip6110. This is necessary when processing pre-eip6110 data with a post-eip6110 `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.
### Upgrading light client data
A eip6110 `LightClientStore` can still process earlier light client data. In order to do so, that pre-eip6110 data needs to be locally upgraded to eip6110 before processing.
```python
def upgrade_lc_header_to_eip6110(pre: deneb.LightClientHeader) -> LightClientHeader:
return LightClientHeader(
beacon=pre.beacon,
execution=ExecutionPayloadHeader(
parent_hash=pre.execution.parent_hash,
fee_recipient=pre.execution.fee_recipient,
state_root=pre.execution.state_root,
receipts_root=pre.execution.receipts_root,
logs_bloom=pre.execution.logs_bloom,
prev_randao=pre.execution.prev_randao,
block_number=pre.execution.block_number,
gas_limit=pre.execution.gas_limit,
gas_used=pre.execution.gas_used,
timestamp=pre.execution.timestamp,
extra_data=pre.execution.extra_data,
base_fee_per_gas=pre.execution.base_fee_per_gas,
block_hash=pre.execution.block_hash,
transactions_root=pre.execution.transactions_root,
withdrawals_root=pre.execution.withdrawals_root,
excess_data_gas=pre.execution.excess_data_gas,
deposit_receipts_root=Root(), # [New in EIP6110]
),
execution_branch=pre.execution_branch,
)
```
```python
def upgrade_lc_bootstrap_to_eip6110(pre: deneb.LightClientBootstrap) -> LightClientBootstrap:
return LightClientBootstrap(
header=upgrade_lc_header_to_eip6110(pre.header),
current_sync_committee=pre.current_sync_committee,
current_sync_committee_branch=pre.current_sync_committee_branch,
)
```
```python
def upgrade_lc_update_to_eip6110(pre: deneb.LightClientUpdate) -> LightClientUpdate:
return LightClientUpdate(
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
next_sync_committee=pre.next_sync_committee,
next_sync_committee_branch=pre.next_sync_committee_branch,
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
finality_branch=pre.finality_branch,
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```
```python
def upgrade_lc_finality_update_to_eip6110(pre: deneb.LightClientFinalityUpdate) -> LightClientFinalityUpdate:
return LightClientFinalityUpdate(
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
finality_branch=pre.finality_branch,
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```
```python
def upgrade_lc_optimistic_update_to_eip6110(pre: deneb.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate:
return LightClientOptimisticUpdate(
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```
### Upgrading the store
Existing `LightClientStore` objects based on Deneb MUST be upgraded to eip6110 before eip6110 based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `EIP6110_FORK_EPOCH`.
```python
def upgrade_lc_store_to_eip6110(pre: deneb.LightClientStore) -> LightClientStore:
if pre.best_valid_update is None:
best_valid_update = None
else:
best_valid_update = upgrade_lc_update_to_eip6110(pre.best_valid_update)
return LightClientStore(
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
current_sync_committee=pre.current_sync_committee,
next_sync_committee=pre.next_sync_committee,
best_valid_update=best_valid_update,
optimistic_header=upgrade_lc_header_to_eip6110(pre.optimistic_header),
previous_max_active_participants=pre.previous_max_active_participants,
current_max_active_participants=pre.current_max_active_participants,
)
```

View File

@ -1,77 +0,0 @@
# EIP-6110 Light Client -- Full Node
**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)
- [Helper functions](#helper-functions)
- [Modified `block_to_light_client_header`](#modified-block_to_light_client_header)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
This upgrade adds information about the execution payload to light client data as part of the EIP-6110 upgrade.
## Helper functions
### Modified `block_to_light_client_header`
```python
def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
epoch = compute_epoch_at_slot(block.message.slot)
if epoch >= CAPELLA_FORK_EPOCH:
payload = block.message.body.execution_payload
execution_header = ExecutionPayloadHeader(
parent_hash=payload.parent_hash,
fee_recipient=payload.fee_recipient,
state_root=payload.state_root,
receipts_root=payload.receipts_root,
logs_bloom=payload.logs_bloom,
prev_randao=payload.prev_randao,
block_number=payload.block_number,
gas_limit=payload.gas_limit,
gas_used=payload.gas_used,
timestamp=payload.timestamp,
extra_data=payload.extra_data,
base_fee_per_gas=payload.base_fee_per_gas,
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals),
)
if epoch >= DENEB_FORK_EPOCH:
execution_header.excess_data_gas = payload.excess_data_gas
# [New in EIP6110]
if epoch >= EIP6110_FORK_EPOCH:
execution_header.deposit_receipts_root = hash_tree_root(payload.deposit_receipts)
execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX)
else:
# Note that during fork transitions, `finalized_header` may still point to earlier forks.
# While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`),
# it was not included in the corresponding light client data. To ensure compatibility
# with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data.
execution_header = ExecutionPayloadHeader()
execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]
return LightClientHeader(
beacon=BeaconBlockHeader(
slot=block.message.slot,
proposer_index=block.message.proposer_index,
parent_root=block.message.parent_root,
state_root=block.message.state_root,
body_root=hash_tree_root(block.message.body),
),
execution=execution_header,
execution_branch=execution_branch,
)
```

View File

@ -1,111 +0,0 @@
# EIP-6110 Light Client -- Networking
**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 -->
- [Networking](#networking)
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [`light_client_finality_update`](#light_client_finality_update)
- [`light_client_optimistic_update`](#light_client_optimistic_update)
- [The Req/Resp domain](#the-reqresp-domain)
- [Messages](#messages)
- [GetLightClientBootstrap](#getlightclientbootstrap)
- [LightClientUpdatesByRange](#lightclientupdatesbyrange)
- [GetLightClientFinalityUpdate](#getlightclientfinalityupdate)
- [GetLightClientOptimisticUpdate](#getlightclientoptimisticupdate)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Networking
The [Deneb light client networking specification](../../deneb/light-client/p2p-interface.md) is extended to exchange [EIP-6110 light client data](./sync-protocol.md).
### The gossip domain: gossipsub
#### Topics and messages
##### Global topics
###### `light_client_finality_update`
[0]: # (eth2spec: skip)
| `fork_version` | Message SSZ type |
|--------------------------------------------------------|-------------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` |
| `DENEB_FORK_VERSION` | `deneb.LightClientFinalityUpdate` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientFinalityUpdate` |
###### `light_client_optimistic_update`
[0]: # (eth2spec: skip)
| `fork_version` | Message SSZ type |
|--------------------------------------------------------|---------------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` |
| `DENEB_FORK_VERSION` | `deneb.LightClientOptimisticUpdate` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientOptimisticUpdate` |
### The Req/Resp domain
#### Messages
##### GetLightClientBootstrap
[0]: # (eth2spec: skip)
| `fork_version` | Response SSZ type |
|--------------------------------------------------------|------------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` |
| `DENEB_FORK_VERSION` | `deneb.LightClientBootstrap` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientBootstrap` |
##### LightClientUpdatesByRange
[0]: # (eth2spec: skip)
| `fork_version` | Response chunk SSZ type |
|--------------------------------------------------------|----------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` |
| `DENEB_FORK_VERSION` | `deneb.LightClientUpdate` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientUpdate` |
##### GetLightClientFinalityUpdate
[0]: # (eth2spec: skip)
| `fork_version` | Response SSZ type |
|--------------------------------------------------------|-------------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` |
| `DENEB_FORK_VERSION` | `deneb.LightClientFinalityUpdate` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientFinalityUpdate` |
##### GetLightClientOptimisticUpdate
[0]: # (eth2spec: skip)
| `fork_version` | Response SSZ type |
|--------------------------------------------------------|---------------------------------------|
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` |
| `DENEB_FORK_VERSION` | `deneb.LightClientOptimisticUpdate` |
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientOptimisticUpdate` |

View File

@ -1,89 +0,0 @@
# EIP-6110 Light Client -- Sync Protocol
**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)
- [Helper functions](#helper-functions)
- [Modified `get_lc_execution_root`](#modified-get_lc_execution_root)
- [Modified `is_valid_light_client_header`](#modified-is_valid_light_client_header)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
This upgrade updates light client data to include the EIP-6110 changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Deneb Light Client specifications](../../deneb/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Deneb based deployments to EIP-6110.
Additional documents describes the impact of the upgrade on certain roles:
- [Full node](./full-node.md)
- [Networking](./p2p-interface.md)
## Helper functions
### Modified `get_lc_execution_root`
```python
def get_lc_execution_root(header: LightClientHeader) -> Root:
epoch = compute_epoch_at_slot(header.beacon.slot)
if epoch >= DENEB_FORK_EPOCH:
return hash_tree_root(header.execution)
if epoch >= CAPELLA_FORK_EPOCH:
execution_header = capella.ExecutionPayloadHeader(
parent_hash=header.execution.parent_hash,
fee_recipient=header.execution.fee_recipient,
state_root=header.execution.state_root,
receipts_root=header.execution.receipts_root,
logs_bloom=header.execution.logs_bloom,
prev_randao=header.execution.prev_randao,
block_number=header.execution.block_number,
gas_limit=header.execution.gas_limit,
gas_used=header.execution.gas_used,
timestamp=header.execution.timestamp,
extra_data=header.execution.extra_data,
base_fee_per_gas=header.execution.base_fee_per_gas,
block_hash=header.execution.block_hash,
transactions_root=header.execution.transactions_root,
withdrawals_root=header.execution.withdrawals_root,
)
return hash_tree_root(execution_header)
return Root()
```
### Modified `is_valid_light_client_header`
```python
def is_valid_light_client_header(header: LightClientHeader) -> bool:
epoch = compute_epoch_at_slot(header.beacon.slot)
# [New in EIP-6110]
if epoch < EIP6110_FORK_EPOCH:
if header.execution.deposit_receipts_root != Root():
return False
if epoch < DENEB_FORK_EPOCH:
if header.execution.excess_data_gas != uint256(0):
return False
if epoch < CAPELLA_FORK_EPOCH:
return (
header.execution == ExecutionPayloadHeader()
and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]
)
return is_valid_merkle_branch(
leaf=get_lc_execution_root(header),
branch=header.execution_branch,
depth=floorlog2(EXECUTION_PAYLOAD_INDEX),
index=get_subtree_index(EXECUTION_PAYLOAD_INDEX),
root=header.beacon.body_root,
)
```

View File

@ -42,16 +42,15 @@
## Introduction
This upgrade adds blobs to the beacon chain as part of Deneb. This is an extension of the Capella upgrade.
The blob transactions are packed into the execution payload by the EL/builder with their corresponding blobs being independently transmitted and are limited by `MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB`. However the CL limit is independently defined by `MAX_BLOBS_PER_BLOCK`.
Deneb is a consensus-layer upgrade containing a number of features. Including:
* [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner.
## Custom types
| Name | SSZ equivalent | Description |
| - | - | - |
| `VersionedHash` | `Bytes32` | |
| `BlobIndex` | `uint64` | |
| `VersionedHash` | `Bytes32` | [New in Deneb:EIP4844] |
| `BlobIndex` | `uint64` | [New in Deneb:EIP4844] |
## Constants
@ -74,8 +73,11 @@ The blob transactions are packed into the execution payload by the EL/builder wi
| Name | Value | Description |
| - | - | - |
| `MAX_BLOB_COMMITMENTS_PER_BLOCK` | `uint64(2**12)` (= 4096) | hardfork independent fixed theoretical limit same as `LIMIT_BLOBS_PER_TX` (see EIP 4844) |
| `MAX_BLOBS_PER_BLOCK` | `uint64(2**2)` (= 4) | Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` |
| `MAX_BLOB_COMMITMENTS_PER_BLOCK` | `uint64(2**12)` (= 4096) | [New in Deneb:EIP4844] hardfork independent fixed theoretical limit same as `LIMIT_BLOBS_PER_TX` (see EIP 4844) |
| `MAX_BLOBS_PER_BLOCK` | `uint64(2**2)` (= 4) | [New in Deneb:EIP4844] Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` |
*Note*: The blob transactions are packed into the execution payload by the EL/builder with their corresponding blobs being independently transmitted
and are limited by `MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB`. However the CL limit is independently defined by `MAX_BLOBS_PER_BLOCK`.
## Configuration
@ -101,9 +103,9 @@ class BeaconBlockBody(Container):
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
sync_aggregate: SyncAggregate
# Execution
execution_payload: ExecutionPayload # [Modified in Deneb]
execution_payload: ExecutionPayload # [Modified in Deneb:EIP4844]
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb:EIP4844]
```
#### `ExecutionPayload`
@ -127,7 +129,8 @@ class ExecutionPayload(Container):
block_hash: Hash32 # Hash of execution block
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
excess_data_gas: uint256 # [New in Deneb]
data_gas_used: uint64 # [New in Deneb:EIP4844]
excess_data_gas: uint64 # [New in Deneb:EIP4844]
```
#### `ExecutionPayloadHeader`
@ -151,7 +154,8 @@ class ExecutionPayloadHeader(Container):
block_hash: Hash32 # Hash of execution block
transactions_root: Root
withdrawals_root: Root
excess_data_gas: uint256 # [New in Deneb]
data_gas_used: uint64 # [New in Deneb:EIP4844]
excess_data_gas: uint64 # [New in Deneb:EIP4844]
```
## Helper functions
@ -204,7 +208,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine,
if not self.is_valid_block_hash(new_payload_request.execution_payload):
return False
# [New in Deneb]
# [New in Deneb:EIP4844]
if not self.is_valid_versioned_hashes(new_payload_request):
return False
@ -231,11 +235,11 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
# Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# [New in Deneb] Verify commitments are under limit
# [New in Deneb:EIP4844] Verify commitments are under limit
assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK
# Verify the execution payload is valid
# [Modified in Deneb] Pass `versioned_hashes` to Execution Engine
# [Modified in Deneb:EIP4844] Pass `versioned_hashes` to Execution Engine
versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments]
assert execution_engine.verify_and_notify_new_payload(
NewPayloadRequest(execution_payload=payload, versioned_hashes=versioned_hashes)
@ -258,7 +262,8 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals),
excess_data_gas=payload.excess_data_gas, # [New in Deneb]
data_gas_used=payload.data_gas_used, # [New in Deneb:EIP4844]
excess_data_gas=payload.excess_data_gas, # [New in Deneb:EIP4844]
)
```

View File

@ -8,7 +8,6 @@
- [Introduction](#introduction)
- [Containers](#containers)
- [Helpers](#helpers)
- [`validate_blobs`](#validate_blobs)
- [`is_data_available`](#is_data_available)
- [Updated fork-choice handlers](#updated-fork-choice-handlers)
- [`on_block`](#on_block)
@ -24,21 +23,12 @@ This is the modification of the fork choice accompanying the Deneb upgrade.
## Helpers
#### `validate_blobs`
```python
def validate_blobs(expected_kzg_commitments: Sequence[KZGCommitment],
blobs: Sequence[Blob],
proofs: Sequence[KZGProof]) -> None:
assert len(expected_kzg_commitments) == len(blobs) == len(proofs)
assert verify_blob_kzg_proof_batch(blobs, expected_kzg_commitments, proofs)
```
#### `is_data_available`
[New in Deneb:EIP4844]
The implementation of `is_data_available` will become more sophisticated during later scaling upgrades.
Initially, verification requires every verifying actor to retrieve all matching `Blob`s and `KZGProof`s, and validate them with `validate_blobs`.
Initially, verification requires every verifying actor to retrieve all matching `Blob`s and `KZGProof`s, and validate them with `verify_blob_kzg_proof_batch`.
The block MUST NOT be considered valid until all valid `Blob`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `Blob`s have subsequently been pruned.
@ -54,7 +44,7 @@ def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZ
if isinstance(blobs, str) or isinstance(proofs, str):
return True
validate_blobs(blob_kzg_commitments, blobs, proofs)
assert verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, proofs)
return True
```
@ -88,7 +78,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
)
assert store.finalized_checkpoint.root == finalized_checkpoint_block
# [New in Deneb]
# [New in Deneb:EIP4844]
# Check if blob data is available
# If not, this block MAY be queued and subsequently considered when blob data becomes available
assert is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments)

View File

@ -83,7 +83,8 @@ def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState:
block_hash=pre.latest_execution_payload_header.block_hash,
transactions_root=pre.latest_execution_payload_header.transactions_root,
withdrawals_root=pre.latest_execution_payload_header.withdrawals_root,
excess_data_gas=uint256(0), # [New in Deneb]
data_gas_used=uint64(0), # [New in Deneb:EIP4844]
excess_data_gas=uint64(0), # [New in Deneb:EIP4844]
)
post = BeaconState(
# Versioning
@ -125,7 +126,7 @@ def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState:
current_sync_committee=pre.current_sync_committee,
next_sync_committee=pre.next_sync_committee,
# Execution-layer
latest_execution_payload_header=latest_execution_payload_header, # [Modified in Deneb]
latest_execution_payload_header=latest_execution_payload_header, # [Modified in Deneb:EIP4844]
# Withdrawals
next_withdrawal_index=pre.next_withdrawal_index,
next_withdrawal_validator_index=pre.next_withdrawal_validator_index,

View File

@ -41,7 +41,8 @@ def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHea
block_hash=pre.execution.block_hash,
transactions_root=pre.execution.transactions_root,
withdrawals_root=pre.execution.withdrawals_root,
excess_data_gas=uint256(0), # [New in Deneb]
data_gas_used=uint64(0), # [New in Deneb:EIP4844]
excess_data_gas=uint64(0), # [New in Deneb:EIP4844]
),
execution_branch=pre.execution_branch,
)

View File

@ -47,8 +47,9 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
withdrawals_root=hash_tree_root(payload.withdrawals),
)
# [New in Deneb]
# [New in Deneb:EIP4844]
if epoch >= DENEB_FORK_EPOCH:
execution_header.data_gas_used = payload.data_gas_used
execution_header.excess_data_gas = payload.excess_data_gas
execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX)

View File

@ -66,9 +66,9 @@ def get_lc_execution_root(header: LightClientHeader) -> Root:
def is_valid_light_client_header(header: LightClientHeader) -> bool:
epoch = compute_epoch_at_slot(header.beacon.slot)
# [New in Deneb]
# [New in Deneb:EIP4844]
if epoch < DENEB_FORK_EPOCH:
if header.execution.excess_data_gas != uint256(0):
if header.execution.data_gas_used != uint64(0) or header.execution.excess_data_gas != uint64(0):
return False
if epoch < CAPELLA_FORK_EPOCH:

View File

@ -50,6 +50,8 @@ The specification of these changes continues in the same format as the network s
#### `BlobSidecar`
[New in Deneb:EIP4844]
```python
class BlobSidecar(Container):
block_root: Root
@ -64,6 +66,8 @@ class BlobSidecar(Container):
#### `SignedBlobSidecar`
[New in Deneb:EIP4844]
```python
class SignedBlobSidecar(Container):
message: BlobSidecar
@ -72,6 +76,8 @@ class SignedBlobSidecar(Container):
#### `BlobIdentifier`
[New in Deneb:EIP4844]
```python
class BlobIdentifier(Container):
block_root: Root
@ -107,7 +113,7 @@ The new topics along with the type of the `data` field of a gossipsub message ar
| Name | Message Type |
| - | - |
| `blob_sidecar_{subnet_id}` | `SignedBlobSidecar` (new) |
| `blob_sidecar_{subnet_id}` | `SignedBlobSidecar` [New in Deneb:EIP4844] |
##### Global topics
@ -124,6 +130,8 @@ New validation:
###### `blob_sidecar_{subnet_id}`
[New in Deneb:EIP4844]
This topic is used to propagate signed blob sidecars, where each blob index maps to some `subnet_id`.
The following validations MUST pass before forwarding the `signed_blob_sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`:
@ -191,7 +199,7 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time.
**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/`
New in deneb.
[New in Deneb:EIP4844]
The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`:
@ -240,7 +248,7 @@ Clients MAY limit the number of blocks and sidecars in the response.
**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/`
New in deneb.
[New in Deneb:EIP4844]
The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`:
@ -269,7 +277,7 @@ Requests blob sidecars in the slot range `[start_slot, start_slot + count)`, lea
The response is unsigned, i.e. `BlobSidecarsByRange`, 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 blob sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `validate_blobs`.
Before consuming the next response chunk, the response reader SHOULD verify the blob sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `verify_blob_kzg_proof_batch`.
`BlobSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` window.

View File

@ -336,7 +336,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
### KZG
KZG core functions. These are also defined in Deneb execution specs.
KZG core functions. These are also defined in Deneb execution specs for EIP-4844.
#### `blob_to_kzg_commitment`

View File

@ -98,6 +98,8 @@ All validator responsibilities remain unchanged other than those noted below.
##### Blob KZG commitments
[New in Deneb:EIP4844]
1. After retrieving the execution payload from the execution engine as specified in Capella,
use the `payload_id` to retrieve `blobs`, `blob_kzg_commitments`, and `blob_kzg_proofs`
via `get_payload(payload_id).blobs_bundle`.

View File

@ -1 +1 @@
1.4.0-alpha.0
1.4.0-alpha.1

View File

@ -1,12 +1,12 @@
from eth2spec.test.context import (
spec_state_test,
with_altair_and_later,
with_light_client,
with_test_suite_name,
)
@with_test_suite_name("BeaconState")
@with_altair_and_later
@with_light_client
@spec_state_test
def test_current_sync_committee_merkle_proof(spec, state):
yield "object", state
@ -27,7 +27,7 @@ def test_current_sync_committee_merkle_proof(spec, state):
@with_test_suite_name("BeaconState")
@with_altair_and_later
@with_light_client
@spec_state_test
def test_next_sync_committee_merkle_proof(spec, state):
yield "object", state
@ -48,7 +48,7 @@ def test_next_sync_committee_merkle_proof(spec, state):
@with_test_suite_name("BeaconState")
@with_altair_and_later
@with_light_client
@spec_state_test
def test_finality_root_merkle_proof(spec, state):
yield "object", state

View File

@ -9,7 +9,7 @@ from eth2spec.test.context import (
with_phases,
with_presets,
with_state,
with_altair_and_later,
with_light_client,
)
from eth2spec.test.helpers.attestations import (
next_slots_with_attestations,
@ -26,7 +26,6 @@ from eth2spec.test.helpers.fork_transition import (
from eth2spec.test.helpers.forks import (
is_post_capella, is_post_deneb,
is_post_fork,
is_post_eip6110,
)
from eth2spec.test.helpers.light_client import (
get_sync_aggregate,
@ -58,10 +57,6 @@ def needs_upgrade_to_deneb(d_spec, s_spec):
return is_post_deneb(s_spec) and not is_post_deneb(d_spec)
def needs_upgrade_to_eip6110(d_spec, s_spec):
return is_post_eip6110(s_spec) and not is_post_eip6110(d_spec)
def check_lc_header_equal(d_spec, s_spec, data, upgraded):
assert upgraded.beacon.slot == data.beacon.slot
assert upgraded.beacon.hash_tree_root() == data.beacon.hash_tree_root()
@ -89,10 +84,6 @@ def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data):
upgraded = s_spec.upgrade_lc_bootstrap_to_deneb(upgraded)
check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded)
if needs_upgrade_to_eip6110(d_spec, s_spec):
upgraded = s_spec.upgrade_lc_bootstrap_to_eip6110(upgraded)
check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded)
return upgraded
@ -154,8 +145,6 @@ class LightClientSyncTest(object):
def get_store_fork_version(s_spec):
if is_post_eip6110(s_spec):
return s_spec.config.EIP6110_FORK_VERSION
if is_post_deneb(s_spec):
return s_spec.config.DENEB_FORK_VERSION
if is_post_capella(s_spec):
@ -301,7 +290,7 @@ def compute_start_slot_at_next_sync_committee_period(spec, state):
return compute_start_slot_at_sync_committee_period(spec, sync_committee_period + 1)
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_light_client_sync(spec, state):
@ -523,7 +512,7 @@ def test_light_client_sync(spec, state):
yield from finish_test(test)
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_supply_sync_committee_from_past_update(spec, state):
@ -553,7 +542,7 @@ def test_supply_sync_committee_from_past_update(spec, state):
yield from finish_test(test)
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_advance_finality_without_sync_committee(spec, state):

View File

@ -1,7 +1,7 @@
from eth2spec.test.context import (
spec_state_test,
with_presets,
with_altair_and_later,
with_light_client,
)
from eth2spec.test.helpers.attestations import (
next_slots_with_attestations,
@ -29,7 +29,7 @@ def create_test_update(spec, test, with_next, with_finality, participation_rate)
)
@with_altair_and_later
@with_light_client
@spec_state_test
@with_presets([MINIMAL], reason="too slow")
def test_update_ranking(spec, state):

View File

@ -3,7 +3,7 @@ from copy import deepcopy
from eth2spec.test.context import (
spec_state_test_with_matching_config,
with_presets,
with_altair_and_later,
with_light_client,
)
from eth2spec.test.helpers.attestations import (
next_epoch_with_attestations,
@ -29,7 +29,7 @@ def setup_test(spec, state):
return (trusted_block, store)
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
def test_process_light_client_update_not_timeout(spec, state):
genesis_block, store = setup_test(spec, state)
@ -61,7 +61,7 @@ def test_process_light_client_update_not_timeout(spec, state):
assert store.current_max_active_participants > 0
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_at_period_boundary(spec, state):
@ -96,7 +96,7 @@ def test_process_light_client_update_at_period_boundary(spec, state):
assert store.current_max_active_participants > 0
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_timeout(spec, state):
@ -131,7 +131,7 @@ def test_process_light_client_update_timeout(spec, state):
assert store.current_max_active_participants > 0
@with_altair_and_later
@with_light_client
@spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_finality_updated(spec, state):

View File

@ -18,6 +18,7 @@ from .helpers.constants import (
MINIMAL, MAINNET,
ALL_PHASES,
ALL_FORK_UPGRADES,
LIGHT_CLIENT_TESTING_FORKS,
)
from .helpers.forks import is_post_fork
from .helpers.typing import SpecForkName, PresetBaseName
@ -428,13 +429,6 @@ def with_all_phases_except(exclusion_phases):
return decorator
with_altair_and_later = with_all_phases_from(ALTAIR)
with_bellatrix_and_later = with_all_phases_from(BELLATRIX)
with_capella_and_later = with_all_phases_from(CAPELLA)
with_deneb_and_later = with_all_phases_from(DENEB)
with_eip6110_and_later = with_all_phases_from(EIP6110)
def _get_preset_targets(kw):
preset_name = DEFAULT_TEST_PRESET
if 'preset' in kw:
@ -540,6 +534,14 @@ def with_presets(preset_bases, reason=None):
return decorator
with_altair_and_later = with_all_phases_from(ALTAIR)
with_bellatrix_and_later = with_all_phases_from(BELLATRIX)
with_capella_and_later = with_all_phases_from(CAPELLA)
with_deneb_and_later = with_all_phases_from(DENEB)
with_eip6110_and_later = with_all_phases_from(EIP6110)
with_light_client = with_phases(LIGHT_CLIENT_TESTING_FORKS)
class quoted_str(str):
pass

View File

@ -16,13 +16,14 @@ from eth2spec.test.helpers.sharding import (
)
def run_block_with_blobs(spec, state, blob_count, excess_data_gas=1, valid=True):
def run_block_with_blobs(spec, state, blob_count, data_gas_used=1, excess_data_gas=1, valid=True):
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.data_gas_used = data_gas_used
block.body.execution_payload.excess_data_gas = excess_data_gas
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)

View File

@ -1,54 +0,0 @@
from eth2spec.test.helpers.state import (
state_transition_and_sign_block,
)
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot
)
from eth2spec.test.context import (
spec_state_test,
with_deneb_and_later,
)
from eth2spec.test.helpers.execution_payload import (
compute_el_block_hash,
)
from eth2spec.test.helpers.sharding import (
get_sample_opaque_tx,
)
def _run_validate_blobs(spec, state, blob_count):
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments, kzg_proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
state_transition_and_sign_block(spec, state, block)
blob_sidecars = spec.get_blob_sidecars(block, blobs, kzg_proofs)
blobs = [sidecar.blob for sidecar in blob_sidecars]
kzg_proofs = [sidecar.kzg_proof for sidecar in blob_sidecars]
spec.validate_blobs(blob_kzg_commitments, blobs, kzg_proofs)
@with_deneb_and_later
@spec_state_test
def test_validate_blobs_zero_blobs(spec, state):
_run_validate_blobs(spec, state, blob_count=0)
@with_deneb_and_later
@spec_state_test
def test_validate_blobs_one_blob(spec, state):
_run_validate_blobs(spec, state, blob_count=1)
@with_deneb_and_later
@spec_state_test
def test_validate_blobs_two_blobs(spec, state):
_run_validate_blobs(spec, state, blob_count=2)
@with_deneb_and_later
@spec_state_test
def test_validate_blobs_max_blobs(spec, state):
_run_validate_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK)

View File

@ -4,6 +4,7 @@ from .typing import SpecForkName, PresetBaseName
#
# SpecForkName
#
# Some of the Spec module functionality is exposed here to deal with phase-specific changes.
PHASE0 = SpecForkName('phase0')
ALTAIR = SpecForkName('altair')
@ -17,15 +18,25 @@ CUSTODY_GAME = SpecForkName('custody_game')
DAS = SpecForkName('das')
EIP6110 = SpecForkName('eip6110')
#
# SpecFork settings
#
# The forks that are deployed on Mainnet
MAINNET_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA)
LATEST_FORK = MAINNET_FORKS[-1]
# The forks that pytest can run with.
ALL_PHASES = (
# Formal forks
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
# Experimental patches
*MAINNET_FORKS,
DENEB,
# Experimental features
EIP6110,
)
# The forks that have light client specs
LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], DENEB)
# The forks that output to the test vectors.
TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110)
TESTGEN_FORKS = (*MAINNET_FORKS, DENEB, EIP6110)
ALL_FORK_UPGRADES = {
# pre_fork_name: post_fork_name
@ -46,7 +57,7 @@ AFTER_DENEB_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items()
AFTER_DENEB_PRE_POST_FORKS = AFTER_DENEB_UPGRADES.items()
#
# Config
# Config and Preset
#
MAINNET = PresetBaseName('mainnet')
MINIMAL = PresetBaseName('minimal')

View File

@ -31,6 +31,7 @@ def get_execution_payload_header(spec, execution_payload):
if is_post_capella(spec):
payload_header.withdrawals_root = spec.hash_tree_root(execution_payload.withdrawals)
if is_post_deneb(spec):
payload_header.data_gas_used = execution_payload.data_gas_used
payload_header.excess_data_gas = execution_payload.excess_data_gas
if is_post_eip6110(spec):
payload_header.deposit_receipts_root = spec.hash_tree_root(execution_payload.deposit_receipts)
@ -98,6 +99,7 @@ def compute_el_header_block_hash(spec,
execution_payload_header_rlp.append((Binary(32, 32), withdrawals_trie_root))
if is_post_deneb(spec):
# excess_data_gas
execution_payload_header_rlp.append((big_endian_int, payload_header.data_gas_used))
execution_payload_header_rlp.append((big_endian_int, payload_header.excess_data_gas))
if is_post_eip6110(spec):
# deposit_receipts_root
@ -201,6 +203,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
if is_post_capella(spec):
payload.withdrawals = spec.get_expected_withdrawals(state)
if is_post_deneb(spec):
payload.data_gas_used = 0
payload.excess_data_gas = 0
if is_post_eip6110(spec):
# just to be clear

View File

@ -1,4 +1,4 @@
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB
from eth2spec.gen_helpers.gen_from_tests.gen import combine_mods, run_state_test_generators
@ -15,14 +15,12 @@ if __name__ == "__main__":
]}
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
deneb_mods = capella_mods
eip6110_mods = deneb_mods
all_mods = {
ALTAIR: altair_mods,
BELLATRIX: bellatrix_mods,
CAPELLA: capella_mods,
DENEB: deneb_mods,
EIP6110: eip6110_mods,
}
run_state_test_generators(runner_name="light_client", all_mods=all_mods)