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

Update block's blob_kzg_commitments size limit to MAX_BLOB_COMMITMENTS_PER_BLOCK (4096) #3338

Merged
merged 11 commits into from
May 24, 2023
2 changes: 2 additions & 0 deletions presets/mainnet/deneb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
# ---------------------------------------------------------------
# `uint64(4096)`
FIELD_ELEMENTS_PER_BLOB: 4096
# `uint64(2**12)` (= 4096)
MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096
# `uint64(2**2)` (= 4)
MAX_BLOBS_PER_BLOCK: 4
2 changes: 2 additions & 0 deletions presets/minimal/deneb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
# ---------------------------------------------------------------
# [customized]
FIELD_ELEMENTS_PER_BLOB: 4
# [customized]
MAX_BLOB_COMMITMENTS_PER_BLOCK: 16
# `uint64(2**2)` (= 4)
MAX_BLOBS_PER_BLOCK: 4
2 changes: 2 additions & 0 deletions specs/_features/eip6110/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
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
# 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(
Expand Down
13 changes: 10 additions & 3 deletions specs/deneb/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@

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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I would put this reference to execution-layer constraints here.

Definitely don't need a reference to "builder", and there is no definition of EL in the consensus-layer specs at this point. If we want to reference that layer use ExecutionEngine


## Custom types

| Name | SSZ equivalent | Description |
Expand Down Expand Up @@ -71,7 +73,8 @@ This upgrade adds blobs to the beacon chain as part of Deneb. This is an extensi

| Name | Value |
| - | - |
| `MAX_BLOBS_PER_BLOCK` | `uint64(2**2)` (= 4) |
| `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` |

## Configuration

Expand Down Expand Up @@ -99,7 +102,7 @@ class BeaconBlockBody(Container):
# Execution
execution_payload: ExecutionPayload # [Modified in Deneb]
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in Deneb]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb]
```

#### `ExecutionPayload`
Expand Down Expand Up @@ -226,8 +229,12 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
# Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)

# [New in Deneb] Verify commitments are under limit
assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK

# Verify the execution payload is valid
# [Modified in Deneb]
# [Modified in Deneb] Pass `versioned_hashes` to Engine API
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)
Expand Down
5 changes: 5 additions & 0 deletions specs/deneb/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ Deneb introduces new global topics for blob sidecars.

The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in deneb.

New 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`
Comment on lines +120 to +123
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@djrtwo I added the p2p validation here. Feel free to open a post-merge PR to revise it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, makes sense!. definitely need the p2p limit given the type isn't protecting us from dos


###### `blob_sidecar_{subnet_id}`

This topic is used to propagate signed blob sidecars, where each blob index maps to some `subnet_id`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,16 @@ def test_invalid_correct_input__execution_invalid(spec, state):

yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments,
valid=False, execution_valid=False)


@with_deneb_and_later
@spec_state_test
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_opaque_tx(spec, blob_count=spec.MAX_BLOBS_PER_BLOCK + 1)

execution_payload.transactions = [opaque_tx]
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)

yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments, valid=False)
20 changes: 16 additions & 4 deletions tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)


def run_block_with_blobs(spec, state, blob_count, excess_data_gas=1):
def run_block_with_blobs(spec, state, blob_count, excess_data_gas=1, valid=True):
yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)
Expand All @@ -25,10 +25,16 @@ def run_block_with_blobs(spec, state, blob_count, excess_data_gas=1):
block.body.execution_payload.transactions = [opaque_tx]
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)
signed_block = state_transition_and_sign_block(spec, state, block)

print(len(block.body.blob_kzg_commitments))

if valid:
signed_block = state_transition_and_sign_block(spec, state, block)
else:
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)

yield 'blocks', [signed_block]
yield 'post', state
yield 'post', state if valid else None


@with_deneb_and_later
Expand All @@ -45,5 +51,11 @@ def test_one_blob(spec, state):

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


@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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from eth2spec.test.context import (
single_phase,
spec_test,
with_deneb_and_later,
)


@with_deneb_and_later
@spec_test
@single_phase
def test_length(spec):
assert spec.MAX_BLOBS_PER_BLOCK < spec.MAX_BLOB_COMMITMENTS_PER_BLOCK