Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MAX_BLOBS_PER_BLOCK_EIP7594 and corresponding configs #4008

Merged
merged 5 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions configs/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128
MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384
SAMPLES_PER_SLOT: 8
CUSTODY_REQUIREMENT: 4
BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8
MAX_BLOBS_PER_BLOCK_EIP7594: 8
# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594`
MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024

# [New in Electra:EIP7251]
MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 # 2**7 * 10**9 (= 128,000,000,000)
Expand Down
4 changes: 4 additions & 0 deletions configs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ DATA_COLUMN_SIDECAR_SUBNET_COUNT: 128
MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384
SAMPLES_PER_SLOT: 8
CUSTODY_REQUIREMENT: 4
BLOB_SIDECAR_SUBNET_COUNT_EIP7594: 8
MAX_BLOBS_PER_BLOCK_EIP7594: 8
# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594`
MAX_REQUEST_BLOB_SIDECARS_EIP7594: 1024

# [New in Electra:EIP7251]
MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 # 2**6 * 10**9 (= 64,000,000,000)
Expand Down
140 changes: 140 additions & 0 deletions specs/_features/eip7594/beacon-chain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# EIP7594 -- 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)
- [Configuration](#configuration)
- [Execution](#execution)
- [Execution payload](#execution-payload)
- [Modified `process_execution_payload`](#modified-process_execution_payload)
- [Testing](#testing)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Introduction

*Note:* This specification is built upon [Electra](../electra/beacon-chain.md) and is under active development.

## Configuration

### Execution

| Name | Value | Description |
| - | - | - |
| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` |

#### Execution payload

##### Modified `process_execution_payload`

```python
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
payload = body.execution_payload

# Verify consistency of the parent hash with respect to the previous execution payload header
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
# Verify prev_randao
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
# Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# Verify commitments are under limit
assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594 # [Modified in EIP7594]
# Verify the execution payload is valid
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,
parent_beacon_block_root=state.latest_block_header.parent_root,
execution_requests=body.execution_requests,
)
)
# Cache execution payload header
state.latest_execution_payload_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),
blob_gas_used=payload.blob_gas_used,
excess_blob_gas=payload.excess_blob_gas,
)
```

## Testing

*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7594 testing only.

```python
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
eth1_timestamp: uint64,
deposits: Sequence[Deposit],
execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader()
) -> BeaconState:
fork = Fork(
previous_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] for testing only
current_version=EIP7594_FORK_VERSION, # [Modified in EIP7594]
epoch=GENESIS_EPOCH,
)
state = BeaconState(
genesis_time=eth1_timestamp + GENESIS_DELAY,
fork=fork,
eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX,
)

# Process deposits
leaves = list(map(lambda deposit: deposit.data, deposits))
for index, deposit in enumerate(deposits):
deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
process_deposit(state, deposit)

# Process deposit balance updates
validator_pubkeys = [v.pubkey for v in state.validators]
for deposit in state.pending_deposits:
validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
increase_balance(state, validator_index, deposit.amount)
state.pending_deposits = []

# Process activations
for index, validator in enumerate(state.validators):
balance = state.balances[index]
validator.effective_balance = min(
balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator))
if validator.effective_balance >= MIN_ACTIVATION_BALANCE:
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH

# Set genesis validators root for domain separation and chain versioning
state.genesis_validators_root = hash_tree_root(state.validators)

# Fill in sync committees
# Note: A duplicate committee is assigned for the current and next committee at genesis
state.current_sync_committee = get_next_sync_committee(state)
state.next_sync_committee = get_next_sync_committee(state)

# Initialize the execution payload header
state.latest_execution_payload_header = execution_payload_header

return state
```
94 changes: 90 additions & 4 deletions specs/_features/eip7594/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
- [MetaData](#metadata)
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [`beacon_block`](#beacon_block)
- [Blob subnets](#blob-subnets)
- [Deprecated `blob_sidecar_{subnet_id}`](#deprecated-blob_sidecar_subnet_id)
- [`data_column_sidecar_{subnet_id}`](#data_column_sidecar_subnet_id)
- [The Req/Resp domain](#the-reqresp-domain)
- [Messages](#messages)
- [BlobSidecarsByRoot v2](#blobsidecarsbyroot-v2)
- [BlobSidecarsByRange v2](#blobsidecarsbyrange-v2)
- [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1)
- [DataColumnSidecarsByRange v1](#datacolumnsidecarsbyrange-v1)
- [GetMetaData v3](#getmetadata-v3)
Expand All @@ -48,10 +52,12 @@

*[New in EIP7594]*

| Name | Value | Description |
|------------------------------------------------|------------------------------------------------|---------------------------------------------------------------------------|
| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request |
| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars |
| Name | Value | Description |
|------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------------------------|
| `MAX_REQUEST_DATA_COLUMN_SIDECARS` | `MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS` | Maximum number of data column sidecars in a single request |
| `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve data column sidecars |
| `MAX_REQUEST_BLOB_SIDECARS_EIP7594` | `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_EIP7594` | Maximum number of blob sidecars in a single request |
| `BLOB_SIDECAR_SUBNET_COUNT_EIP7594` | `2**3` (= 8) | The number of blob sidecar subnets used in the gossipsub protocol |

### Containers

Expand Down Expand Up @@ -154,6 +160,15 @@ Some gossip meshes are upgraded in the EIP-7594 fork to support upgraded types.

#### Topics and messages

##### Global topics

###### `beacon_block`

*Updated validation*

- _[REJECT]_ The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer --
i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594`

##### Blob subnets

###### Deprecated `blob_sidecar_{subnet_id}`
Expand Down Expand Up @@ -189,6 +204,75 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi

#### Messages

##### BlobSidecarsByRoot v2

**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/`

*[Updated in EIP7594]*

The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`:

[1]: # (eth2spec: skip)

| `fork_version` | Chunk SSZ type |
|------------------------|-----------------------|
| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` |

Request Content:

```
(
List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_EIP7594]
)
```

Response Content:

```
(
List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594]
)
```

*Updated validation*

No more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` may be requested at a time.

##### BlobSidecarsByRange v2

**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/2/`

*[Updated in EIP7594]*

The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`:

[1]: # (eth2spec: skip)

| `fork_version` | Chunk SSZ type |
|------------------------|-----------------------|
| `EIP7594_FORK_VERSION` | `eip7594.BlobSidecar` |

Request Content:

```
(
start_slot: Slot
count: uint64
)
```

Response Content:

```
(
List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS_EIP7594]
)
```

*Updated validation*

Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_EIP7594` sidecars.

##### DataColumnSidecarsByRoot v1

**Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_root/1/`
Expand Down Expand Up @@ -252,6 +336,7 @@ The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork
| `EIP7594_FORK_VERSION` | `eip7594.DataColumnSidecar` |

Request Content:

```
(
start_slot: Slot
Expand All @@ -261,6 +346,7 @@ Request Content:
```

Response Content:

```
(
List[DataColumnSidecar, MAX_REQUEST_DATA_COLUMN_SIDECARS]
Expand Down
2 changes: 1 addition & 1 deletion specs/deneb/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Deneb is a consensus-layer upgrade containing a number of features. Including:

| Name | Value | Description |
| - | - | - |
| `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_BLOB_COMMITMENTS_PER_BLOCK` | `uint64(2**12)` (= 4096) | *[New in Deneb:EIP4844]* hardfork independent fixed theoretical limit same as `TARGET_BLOB_GAS_PER_BLOCK` (see EIP 4844) |

## Configuration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
)
from eth2spec.test.helpers.blob import (
get_sample_blob_tx,
get_max_blob_count,
)


Expand Down Expand Up @@ -254,7 +255,7 @@ def test_invalid_correct_input__execution_invalid(spec, state):
def test_invalid_exceed_max_blobs_per_block(spec, state):
execution_payload = build_empty_execution_payload(spec, state)

opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=spec.config.MAX_BLOBS_PER_BLOCK + 1)
opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=get_max_blob_count(spec) + 1)

execution_payload.transactions = [opaque_tx]
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload, state)
Expand Down
11 changes: 6 additions & 5 deletions tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from eth2spec.test.helpers.blob import (
get_sample_blob_tx,
get_max_blob_count,
)


Expand Down Expand Up @@ -72,31 +73,31 @@ def test_one_blob_two_txs(spec, state):
@with_deneb_and_later
@spec_state_test
def test_one_blob_max_txs(spec, state):
yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=spec.MAX_BLOBS_PER_BLOCK)
yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=get_max_blob_count(spec))


@with_deneb_and_later
@spec_state_test
def test_invalid_one_blob_max_plus_one_txs(spec, state):
yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=spec.MAX_BLOBS_PER_BLOCK + 1, valid=False)
yield from run_block_with_blobs(spec, state, blob_count=1, tx_count=get_max_blob_count(spec) + 1, valid=False)


@with_deneb_and_later
@spec_state_test
def test_max_blobs_per_block(spec, state):
yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK)
yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec))


@with_deneb_and_later
@spec_state_test
def test_invalid_max_blobs_per_block_two_txs(spec, state):
yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK, tx_count=2, valid=False)
yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec), tx_count=2, valid=False)


@with_deneb_and_later
@spec_state_test
def test_invalid_exceed_max_blobs_per_block(spec, state):
yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK + 1, valid=False)
yield from run_block_with_blobs(spec, state, blob_count=get_max_blob_count(spec) + 1, valid=False)


@with_deneb_and_later
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,16 @@ def test_invariants(spec):
@single_phase
def test_polynomical_commitments_sampling(spec):
assert spec.FIELD_ELEMENTS_PER_EXT_BLOB == 2 * spec.FIELD_ELEMENTS_PER_BLOB


@with_eip7594_and_later
@spec_test
@single_phase
def test_networking(spec):
assert spec.config.MAX_BLOBS_PER_BLOCK_EIP7594 <= spec.MAX_BLOB_COMMITMENTS_PER_BLOCK
assert (
spec.config.MAX_REQUEST_BLOB_SIDECARS_EIP7594 ==
spec.config.MAX_REQUEST_BLOCKS_DENEB * spec.config.MAX_BLOBS_PER_BLOCK_EIP7594
)
# Start with the same size, but `BLOB_SIDECAR_SUBNET_COUNT` could potentially increase later.
assert spec.config.BLOB_SIDECAR_SUBNET_COUNT_EIP7594 == spec.config.MAX_BLOBS_PER_BLOCK_EIP7594
Loading