Skip to content

Commit

Permalink
Merge pull request #4008 from ethereum/eip7594-param
Browse files Browse the repository at this point in the history
Add `MAX_BLOBS_PER_BLOCK_EIP7594` and corresponding configs
  • Loading branch information
jtraglia authored Nov 20, 2024
2 parents af72bae + 5753be7 commit ec9460d
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 14 deletions.
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

0 comments on commit ec9460d

Please sign in to comment.