diff --git a/setup.py b/setup.py index b1ab11c38a..5dfe29c2ae 100644 --- a/setup.py +++ b/setup.py @@ -726,7 +726,9 @@ def execution_engine_cls(cls) -> str: return "\n\n" + """ class NoopExecutionEngine(ExecutionEngine): - def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: return True def notify_forkchoice_updated(self: ExecutionEngine, @@ -740,7 +742,9 @@ def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadRespo # pylint: disable=unused-argument raise NotImplementedError("no default block production") - def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: + def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: return True def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: diff --git a/specs/_features/eip4788/beacon-chain.md b/specs/_features/eip4788/beacon-chain.md deleted file mode 100644 index 6cd876de99..0000000000 --- a/specs/_features/eip4788/beacon-chain.md +++ /dev/null @@ -1,72 +0,0 @@ -# EIP-4788 -- The Beacon Chain - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Containers](#containers) - - [Extended Containers](#extended-containers) - - [`ExecutionPayload`](#executionpayload) - - [`ExecutionPayloadHeader`](#executionpayloadheader) - - - - -## Introduction - -TODO - -## Containers - -### Extended Containers - -#### `ExecutionPayload` - -```python -class ExecutionPayload(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress # 'beneficiary' in the yellow paper - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 # 'difficulty' in the yellow paper - block_number: uint64 # 'number' in the yellow paper - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 # Hash of execution block - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - parent_beacon_block_root: Root # [New in EIP-4788] -``` - -#### `ExecutionPayloadHeader` - -```python -class ExecutionPayloadHeader(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 # Hash of execution block - transactions_root: Root - withdrawals_root: Root - parent_beacon_block_root: Root # [New in EIP-4788] -``` diff --git a/specs/_features/eip4788/validator.md b/specs/_features/eip4788/validator.md deleted file mode 100644 index 11462bda1d..0000000000 --- a/specs/_features/eip4788/validator.md +++ /dev/null @@ -1,88 +0,0 @@ -# EIP-4788 -- Honest Validator - -**Notice**: This document is a work-in-progress for researchers and implementers. - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Prerequisites](#prerequisites) -- [Helpers](#helpers) -- [Protocols](#protocols) - - [`ExecutionEngine`](#executionengine) - - [Modified `get_payload`](#modified-get_payload) -- [Beacon chain responsibilities](#beacon-chain-responsibilities) - - [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayload](#executionpayload) - - - - -## Introduction - -This document represents the changes to be made in the code of an "honest validator" to implement the EIP-4788 feature. - -## Prerequisites - -This document is an extension of the [Capella -- Honest Validator](../capella/validator.md) guide. -All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. - -All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [Capella](../capella/beacon-chain.md) are requisite for this document and used throughout. -Please see related Beacon Chain doc before continuing and use them as a reference throughout. - -## Helpers - -## Protocols - -### `ExecutionEngine` - -#### Modified `get_payload` - -`get_payload` returns the upgraded EIP-4788 `ExecutionPayload` type. - -## Beacon chain responsibilities - -All validator responsibilities remain unchanged other than those noted below. - -### Block proposal - -#### Constructing the `BeaconBlockBody` - -##### ExecutionPayload - -`ExecutionPayload`s are constructed as they were in Capella, except that the parent beacon block root is also supplied. - -*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. -That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. - -*Note*: The only change made to `prepare_execution_payload` is to add the parent beacon block root as an additional -parameter to the `PayloadAttributes`. - -```python -def prepare_execution_payload(state: BeaconState, - safe_block_hash: Hash32, - finalized_block_hash: Hash32, - suggested_fee_recipient: ExecutionAddress, - execution_engine: ExecutionEngine) -> Optional[PayloadId]: - # Verify consistency of the parent hash with respect to the previous execution payload header - parent_hash = state.latest_execution_payload_header.block_hash - - # Set the forkchoice head and initiate the payload build process - payload_attributes = PayloadAttributes( - timestamp=compute_timestamp_at_slot(state, state.slot), - prev_randao=get_randao_mix(state, get_current_epoch(state)), - suggested_fee_recipient=suggested_fee_recipient, - withdrawals=get_expected_withdrawals(state), - parent_beacon_block_root=hash_tree_root(state.latest_block_header), # [New in EIP-4788] - ) - return execution_engine.notify_forkchoice_updated( - head_block_hash=parent_hash, - safe_block_hash=safe_block_hash, - finalized_block_hash=finalized_block_hash, - payload_attributes=payload_attributes, - ) -``` diff --git a/specs/_features/eip6110/beacon-chain.md b/specs/_features/eip6110/beacon-chain.md index 1bfa29138a..44980685c4 100644 --- a/specs/_features/eip6110/beacon-chain.md +++ b/specs/_features/eip6110/beacon-chain.md @@ -224,7 +224,7 @@ def process_deposit_receipt(state: BeaconState, deposit_receipt: DepositReceipt) state.deposit_receipts_start_index = deposit_receipt.index apply_deposit( - state=state, + state=state, pubkey=deposit_receipt.pubkey, withdrawal_credentials=deposit_receipt.withdrawal_credentials, amount=deposit_receipt.amount, @@ -251,7 +251,11 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # 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) + NewPayloadRequest( + execution_payload=payload, + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + ) ) # Cache execution payload header state.latest_execution_payload_header = ExecutionPayloadHeader( diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index b2bbf76160..9228a7d8f3 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -31,7 +31,9 @@ - [Request data](#request-data) - [Modified `NewPayloadRequest`](#modified-newpayloadrequest) - [Engine APIs](#engine-apis) + - [`is_valid_block_hash`](#is_valid_block_hash) - [`is_valid_versioned_hashes`](#is_valid_versioned_hashes) + - [Modified `notify_new_payload`](#modified-notify_new_payload) - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) - [Modified `process_attestation`](#modified-process_attestation) @@ -46,6 +48,7 @@ ## Introduction Deneb is a consensus-layer upgrade containing a number of features. Including: +* [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788): Beacon block root in the EVM * [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner * [EIP-7044](https://github.com/ethereum/EIPs/pull/7044): Perpetually Valid Signed Voluntary Exits * [EIP-7045](https://eips.ethereum.org/EIPS/eip-7045): Increase Max Attestation Inclusion Slot @@ -221,10 +224,23 @@ def get_attestation_participation_flag_indices(state: BeaconState, class NewPayloadRequest(object): execution_payload: ExecutionPayload versioned_hashes: Sequence[VersionedHash] + parent_beacon_block_root: Root ``` #### Engine APIs +##### `is_valid_block_hash` + +```python +def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + """ + Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly. + """ + ... +``` + ##### `is_valid_versioned_hashes` ```python @@ -236,6 +252,18 @@ def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPay ... ``` +##### Modified `notify_new_payload` + +```python +def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + """ + Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. + """ + ... +``` + ##### Modified `verify_and_notify_new_payload` ```python @@ -244,14 +272,19 @@ def verify_and_notify_new_payload(self: ExecutionEngine, """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ - if not self.is_valid_block_hash(new_payload_request.execution_payload): + execution_payload = new_payload_request.execution_payload + parent_beacon_block_root = new_payload_request.parent_beacon_block_root + + # [New in Deneb:EIP4788] + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False # [New in Deneb:EIP4844] if not self.is_valid_versioned_hashes(new_payload_request): return False - if not self.notify_new_payload(new_payload_request.execution_payload): + # [New in Deneb:EIP4788] + if not self.notify_new_payload(execution_payload, parent_beacon_block_root): return False return True @@ -303,7 +336,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Modified `process_execution_payload` -*Note*: The function `process_execution_payload` is modified to pass `versioned_hashes` into `execution_engine.verify_and_notify_new_payload` and to assign the new fields in `ExecutionPayloadHeader` for EIP-4844. +*Note*: The function `process_execution_payload` is modified to pass `versioned_hashes` into `execution_engine.verify_and_notify_new_payload` and to assign the new fields in `ExecutionPayloadHeader` for EIP-4844. It is also modified to pass in the parent beacon block root to support EIP-4788. ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: @@ -321,9 +354,14 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify the execution payload is valid # [Modified in Deneb:EIP4844] Pass `versioned_hashes` to Execution Engine + # [Modified in Deneb:EIP4788] Pass parent beacon block root 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) + NewPayloadRequest( + execution_payload=payload, + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + ) ) # Cache execution payload header diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index bbc7fa0f89..d7d2eaa2fc 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -8,7 +8,8 @@ - [Introduction](#introduction) - [Containers](#containers) - [Helpers](#helpers) - - [`is_data_available`](#is_data_available) + - [Extended `PayloadAttributes`](#extended-payloadattributes) + - [`is_data_available`](#is_data_available) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -23,7 +24,21 @@ This is the modification of the fork choice accompanying the Deneb upgrade. ## Helpers -#### `is_data_available` +### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the parent beacon block root. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root # [New in Deneb:EIP4788] +``` + +### `is_data_available` *[New in Deneb:EIP4844]* diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 3157ccf218..7b8a81b19a 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -19,6 +19,7 @@ - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block and sidecar proposal](#block-and-sidecar-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayload](#executionpayload) - [Blob KZG commitments](#blob-kzg-commitments) - [Constructing the `SignedBlobSidecar`s](#constructing-the-signedblobsidecars) - [Sidecar](#sidecar) @@ -88,11 +89,46 @@ All validator responsibilities remain unchanged other than those noted below. #### Constructing the `BeaconBlockBody` +##### ExecutionPayload + +`prepare_execution_payload` is updated from the Capella specs to provide the parent beacon block root. + +*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. +That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. + +*Note*: The only change made to `prepare_execution_payload` is to add the parent beacon block root as an additional +parameter to the `PayloadAttributes`. + +```python +def prepare_execution_payload(state: BeaconState, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + execution_engine: ExecutionEngine) -> Optional[PayloadId]: + # Verify consistency of the parent hash with respect to the previous execution payload header + parent_hash = state.latest_execution_payload_header.block_hash + + # Set the forkchoice head and initiate the payload build process + payload_attributes = PayloadAttributes( + timestamp=compute_timestamp_at_slot(state, state.slot), + prev_randao=get_randao_mix(state, get_current_epoch(state)), + suggested_fee_recipient=suggested_fee_recipient, + withdrawals=get_expected_withdrawals(state), + parent_beacon_block_root=hash_tree_root(state.latest_block_header), # [New in Deneb:EIP4788] + ) + return execution_engine.notify_forkchoice_updated( + head_block_hash=parent_hash, + safe_block_hash=safe_block_hash, + finalized_block_hash=finalized_block_hash, + payload_attributes=payload_attributes, + ) +``` + ##### Blob KZG commitments *[New in Deneb:EIP4844]* -1. After retrieving the execution payload from the execution engine as specified in Capella, +1. After retrieving the execution payload from the execution engine as specified above, use the `payload_id` to retrieve `blobs`, `blob_kzg_commitments`, and `blob_kzg_proofs` via `get_payload(payload_id).blobs_bundle`. 2. Set `block.body.blob_kzg_commitments = blob_kzg_commitments`.