commit
2c3a47e1c1
4
setup.py
4
setup.py
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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]
|
||||
)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
```
|
|
@ -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,
|
||||
)
|
||||
```
|
|
@ -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` |
|
|
@ -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,
|
||||
)
|
||||
```
|
|
@ -126,7 +126,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]
|
||||
excess_data_gas: uint64 # [New in Deneb]
|
||||
```
|
||||
|
||||
#### `ExecutionPayloadHeader`
|
||||
|
@ -150,7 +151,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]
|
||||
excess_data_gas: uint64 # [New in Deneb]
|
||||
```
|
||||
|
||||
## Helper functions
|
||||
|
@ -257,6 +259,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, # [New in Deneb]
|
||||
excess_data_gas=payload.excess_data_gas, # [New in Deneb]
|
||||
)
|
||||
```
|
||||
|
|
|
@ -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,10 @@ 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`
|
||||
|
||||
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 +42,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
|
||||
```
|
||||
|
||||
|
|
|
@ -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]
|
||||
excess_data_gas=uint64(0), # [New in Deneb]
|
||||
)
|
||||
post = BeaconState(
|
||||
# Versioning
|
||||
|
|
|
@ -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]
|
||||
excess_data_gas=uint64(0), # [New in Deneb]
|
||||
),
|
||||
execution_branch=pre.execution_branch,
|
||||
)
|
||||
|
|
|
@ -49,6 +49,7 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
|
|||
|
||||
# [New in Deneb]
|
||||
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)
|
||||
|
|
|
@ -68,7 +68,7 @@ def is_valid_light_client_header(header: LightClientHeader) -> bool:
|
|||
|
||||
# [New in Deneb]
|
||||
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:
|
||||
|
|
|
@ -269,7 +269,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.
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.4.0-alpha.0
|
||||
1.4.0-alpha.1
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue