diff --git a/.gitignore b/.gitignore index 474db02c58..8d008f2c98 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ tests/core/pyspec/eth2spec/eip7002/ tests/core/pyspec/eth2spec/whisk/ +tests/core/pyspec/eth2spec/eip7547/ tests/core/pyspec/eth2spec/eip7594/ # coverage reports diff --git a/Makefile b/Makefile index d0d750e893..a8aa486b9e 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb eip6110 eip7002 whisk +ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb eip6110 eip7002 whisk eip7547 # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index d31634958a..25dbd580cf 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -56,6 +56,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000000 # temporary stub EIP7002_FORK_EPOCH: 18446744073709551615 +# EIP7547 +EIP7547_FORK_VERSION: 0x06000000 # temporary stub +EIP7547_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 6b2da84fdb..11c332c660 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -55,6 +55,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000001 EIP7002_FORK_EPOCH: 18446744073709551615 +# EIP7547 +EIP7547_FORK_VERSION: 0x06000001 +EIP7547_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000001 WHISK_FORK_EPOCH: 18446744073709551615 diff --git a/pysetup/constants.py b/pysetup/constants.py index 238b3b02ce..0748bc8e62 100644 --- a/pysetup/constants.py +++ b/pysetup/constants.py @@ -7,10 +7,10 @@ EIP6110 = 'eip6110' EIP7002 = 'eip7002' WHISK = 'whisk' +EIP7547 = 'eip7547' EIP7594 = 'eip7594' - # The helper functions that are used when defining constants CONSTANT_DEP_SUNDRY_CONSTANTS_FUNCTIONS = ''' def ceillog2(x: int) -> uint64: diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index c93c0c0321..32347c9b54 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -9,6 +9,7 @@ EIP6110, WHISK, EIP7002, + EIP7547, EIP7594, ) @@ -22,6 +23,7 @@ EIP6110: DENEB, WHISK: CAPELLA, EIP7002: CAPELLA, + EIP7547: DENEB, EIP7594: DENEB, } diff --git a/pysetup/spec_builders/__init__.py b/pysetup/spec_builders/__init__.py index 061d11626d..93c7a5717f 100644 --- a/pysetup/spec_builders/__init__.py +++ b/pysetup/spec_builders/__init__.py @@ -7,12 +7,13 @@ from .eip7002 import EIP7002SpecBuilder from .whisk import WhiskSpecBuilder from .eip7594 import EIP7594SpecBuilder +from .eip7547 import EIP7547SpecBuilder spec_builders = { builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, EIP7002SpecBuilder, WhiskSpecBuilder, EIP7594SpecBuilder, + EIP6110SpecBuilder, EIP7002SpecBuilder, WhiskSpecBuilder, EIP7594SpecBuilder, EIP7547SpecBuilder, ) } diff --git a/pysetup/spec_builders/eip7547.py b/pysetup/spec_builders/eip7547.py new file mode 100644 index 0000000000..605d312634 --- /dev/null +++ b/pysetup/spec_builders/eip7547.py @@ -0,0 +1,63 @@ +from .base import BaseSpecBuilder +from ..constants import EIP7547 + + +class EIP7547SpecBuilder(BaseSpecBuilder): + fork: str = EIP7547 + + @classmethod + def sundry_functions(cls) -> str: + return ''' +def retrieve_inclusion_list(slot: Slot, proposer_index: ValidatorIndex) -> InclusionList: + # pylint: disable=unused-argument + ... +''' + + @classmethod + def execution_engine_cls(cls) -> str: + return """ +class NoopExecutionEngine(ExecutionEngine): + + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + return True + + def notify_forkchoice_updated(self: ExecutionEngine, + head_block_hash: Hash32, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]: + pass + + def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse: + # pylint: disable=unused-argument + raise NotImplementedError("no default block production") + + 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: + return True + + def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + return True + + def notify_new_inclusion_list(self: ExecutionEngine, + inclusion_list_request: NewInclusionListRequest) -> bool: + return True + + def get_execution_inclusion_list(self: ExecutionEngine, parent_block_hash: Root) -> GetInclusionListResponse: + return GetInclusionListResponse() + + +EXECUTION_ENGINE = NoopExecutionEngine()""" + + @classmethod + def imports(cls, preset_name: str): + return f''' +from eth2spec.deneb import {preset_name} as deneb +''' diff --git a/specs/_features/eip7547/beacon-chain.md b/specs/_features/eip7547/beacon-chain.md new file mode 100644 index 0000000000..98f38f718e --- /dev/null +++ b/specs/_features/eip7547/beacon-chain.md @@ -0,0 +1,79 @@ +# EIP-7547 -- The Beacon Chain + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Preset](#preset) + - [Execution](#execution) +- [Containers](#containers) + - [New Containers](#new-containers) + - [`InclusionListSummaryEntry`](#inclusionlistsummaryentry) + - [`InclusionListSummary`](#inclusionlistsummary) + - [Extended containers](#extended-containers) + - [`BeaconBlockBody`](#beaconblockbody) + + + + +## Introduction + +This is the beacon chain specification to add an inclusion list mechanism to allow forced transaction inclusion. Refers to [EIP-7547](https://eips.ethereum.org/EIPS/eip-7547). + +*Note:* This specification is built upon [Deneb](../../deneb/beacon_chain.md) and is under active development. + +## Preset + +### Execution + +| Name | Value | +| - | - | +| `MAX_TRANSACTIONS_PER_INCLUSION_LIST` | `uint64(2**4)` (= 16) | +| `MAX_GAS_PER_INCLUSION_LIST` | `uint64(2**21)` (= 2,097,152) | + +## Containers + +### New Containers + +#### `InclusionListSummaryEntry` + +```python +class InclusionListSummaryEntry(Container): + address: ExecutionAddress + gas_limit: uint64 +``` + +#### `InclusionListSummary` + +```python +class InclusionListSummary(Container): + slot: Slot + proposer_index: ValidatorIndex + summary: List[InclusionListSummaryEntry, MAX_TRANSACTIONS_PER_INCLUSION_LIST] +``` + +### Extended containers + +#### `BeaconBlockBody` + +```python +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data # Eth1 data vote + graffiti: Bytes32 # Arbitrary data + # Operations + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + sync_aggregate: SyncAggregate + # Execution + execution_payload: ExecutionPayload # [Modified in Deneb:EIP4844] + bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + inclusion_list_summary: InclusionListSummary # [New in EIP7547] +``` \ No newline at end of file diff --git a/specs/_features/eip7547/fork-choice.md b/specs/_features/eip7547/fork-choice.md new file mode 100644 index 0000000000..8d877192fc --- /dev/null +++ b/specs/_features/eip7547/fork-choice.md @@ -0,0 +1,59 @@ +# EIP-7547 -- Fork Choice + +## Table of contents + + + + +- [Introduction](#introduction) +- [Preset](#preset) + - [Execution](#execution) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [Request data](#request-data) + - [Extended `PayloadAttributes`](#extended-payloadattributes) + - [Engine APIs](#engine-apis) + - [Extended `notify_forkchoice_updated`](#extended-notify_forkchoice_updated) + + + + +## Introduction + +This is the modification of the fork choice accompanying the EIP7547 upgrade. + +## Preset + +### Execution + +| Name | Value | +| - | - | +| `MAX_TRANSACTIONS_PER_INCLUSION_LIST` | `uint64(2**4)` (= 16) | + +## Protocols + +### `ExecutionEngine` + +#### Request data + +##### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the inclusion list transactions that are passed from the CL to the EL when requesting block constructions. We change the content of `notify_forkchoice_updated` accordingly. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root + inclusion_list_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST] # [New in EIP7547] +``` + +#### Engine APIs + +##### Extended `notify_forkchoice_updated` + +The only change made is to the `PayloadAttributes` container with the extended `PayloadAttributes`. +Otherwise, `notify_forkchoice_updated` inherits all prior functionality. diff --git a/specs/_features/eip7547/fork.md b/specs/_features/eip7547/fork.md new file mode 100644 index 0000000000..803210df81 --- /dev/null +++ b/specs/_features/eip7547/fork.md @@ -0,0 +1,123 @@ +# EIP7547 -- Fork Logic + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + +- [Introduction](#introduction) +- [Configuration](#configuration) +- [Helper functions](#helper-functions) + - [Misc](#misc) + - [Modified `compute_fork_version`](#modified-compute_fork_version) +- [Fork to EIP7547](#fork-to-eip7547) + - [Fork trigger](#fork-trigger) + - [Upgrading the state](#upgrading-the-state) + + + +## Introduction + +This document describes the process of EIP7547 upgrade. + +## Configuration + +Warning: this configuration is not definitive. + +| Name | Value | +| - | - | +| `EIP7547_FORK_VERSION` | `Version('0x05000000')` | +| `EIP7547_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | + +## Helper functions + +### Misc + +#### Modified `compute_fork_version` + +```python +def compute_fork_version(epoch: Epoch) -> Version: + """ + Return the fork version at the given ``epoch``. + """ + if epoch >= EIP7547_FORK_EPOCH: + return EIP7547_FORK_VERSION + if epoch >= DENEB_FORK_EPOCH: + return DENEB_FORK_VERSION + if epoch >= CAPELLA_FORK_EPOCH: + return CAPELLA_FORK_VERSION + if epoch >= BELLATRIX_FORK_EPOCH: + return BELLATRIX_FORK_VERSION + if epoch >= ALTAIR_FORK_EPOCH: + return ALTAIR_FORK_VERSION + return GENESIS_FORK_VERSION +``` + +## Fork to EIP7547 + +### Fork trigger + +For now, we assume the condition will be triggered at epoch `EIP7547_FORK_EPOCH`. + +Note that for the pure EIP7547 networks, we don't apply `upgrade_to_EIP7547` since it starts with EIP7547 version logic. + +### Upgrading the state + +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7547_FORK_EPOCH`, +an irregular state change is made to upgrade to EIP7547. + +```python +def upgrade_to_EIP7547(pre: deneb.BeaconState) -> BeaconState: + epoch = deneb.get_current_epoch(pre) + post = BeaconState( + # Versioning + genesis_time=pre.genesis_time, + genesis_validators_root=pre.genesis_validators_root, + slot=pre.slot, + fork=Fork( + previous_version=pre.fork.current_version, + current_version=EIP7547_FORK_VERSION, # [Modified in EIP7547] + epoch=epoch, + ), + # History + latest_block_header=pre.latest_block_header, + block_roots=pre.block_roots, + state_roots=pre.state_roots, + historical_roots=pre.historical_roots, + # Eth1 + eth1_data=pre.eth1_data, + eth1_data_votes=pre.eth1_data_votes, + eth1_deposit_index=pre.eth1_deposit_index, + # Registry + validators=pre.validators, + balances=pre.balances, + # Randomness + randao_mixes=pre.randao_mixes, + # Slashings + slashings=pre.slashings, + # Participation + previous_epoch_participation=pre.previous_epoch_participation, + current_epoch_participation=pre.current_epoch_participation, + # Finality + justification_bits=pre.justification_bits, + previous_justified_checkpoint=pre.previous_justified_checkpoint, + current_justified_checkpoint=pre.current_justified_checkpoint, + finalized_checkpoint=pre.finalized_checkpoint, + # Inactivity + inactivity_scores=pre.inactivity_scores, + # Sync + current_sync_committee=pre.current_sync_committee, + next_sync_committee=pre.next_sync_committee, + # Execution-layer + latest_execution_payload_header=pre.latest_execution_payload_header, + # Withdrawals + next_withdrawal_index=pre.next_withdrawal_index, + next_withdrawal_validator_index=pre.next_withdrawal_validator_index, + # Deep history valid from Capella onwards + historical_summaries=pre.historical_summaries, + ) + + return post +``` diff --git a/specs/_features/eip7547/p2p-networking.md b/specs/_features/eip7547/p2p-networking.md new file mode 100644 index 0000000000..87eb041256 --- /dev/null +++ b/specs/_features/eip7547/p2p-networking.md @@ -0,0 +1,93 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [EIP-7547 -- Networking](#eip-7547----networking) + - [Preset](#preset) + - [Execution](#execution) + - [Containers](#containers) + - [New Containers](#new-containers) + - [`SignedInclusionListTransactions`](#signedinclusionlisttransactions) + - [`SignedBeaconBlockAndInclusionList`](#signedbeaconblockandinclusionlist) + - [Modifications in EIP7547](#modifications-in-eip7547) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [Transitioning the gossip](#transitioning-the-gossip) + - [Design rationale](#design-rationale) + - [Why is it proposer may send multiple inclusion lists? Why not just one per slot?](#why-is-it-proposer-may-send-multiple-inclusion-lists-why-not-just-one-per-slot) + + + +# EIP-7547 -- Networking + +This document contains the consensus-layer networking specification for EIP-7547. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + +## Preset + +### Execution + +| Name | Value | +| - | - | +| `MAX_TRANSACTIONS_PER_INCLUSION_LIST` | `uint64(2**4)` (= 16) | + +## Containers + +### New Containers + +#### `SignedInclusionListTransactions` + +```python +class SignedInclusionListTransactions(Container): + transactions: transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + signature: BLSSignature +``` + +#### `SignedBeaconBlockAndInclusionList` + +```python +class SignedBeaconBlockAndInclusionList(Container): + signed_block: SignedBeaconBlock + signed_transactions: SignedInclusionListTransactions +``` + +## Modifications in EIP7547 + +### The gossip domain: gossipsub + +Some gossip meshes are upgraded in the fork for EIP7547 to support upgraded types. + +#### Topics and messages + +Topics follow the same specification as in prior upgrades. + +The derivation of the `message-id` remains stable. + +##### Global topics + +###### `beacon_block` + +The *type* of the payload of this topic changes to the (modified) `BeaconBlockAndInclusionList`. + +New validation: + +The following validations MUST pass before forwarding the `beacon_block` on the network. + +- _[REJECT]_ The inclusion list transactions `beacon_block.transactions` length is within upperbound `MAX_TRANSACTIONS_PER_INCLUSION_LIST`. +- _[REJECT]_ The inclusion list summary has the same length of transactions `len(beacon_block.signed_block.inclusion_list_summary) == len(beacon_block.transactions)`. +- _[REJECT]_ The inclusion list transactions signature, `beacon_block.signed_transactions.signature`, is valid with respect to the `proposer_index` pubkey. +- _[REJECT]_ The summary is proposed by the expected proposer_index for the summary's slot in the context of the current shuffling (defined by parent_root/slot). If the proposer_index cannot immediately be verified against the expected shuffling, the inclusion list MAY be queued for later processing while proposers for the summary's branch are calculated -- in such a case do not REJECT, instead IGNORE this message. + +#### Transitioning the gossip + +See gossip transition details found in the [Deneb document](../deneb/p2p-interface.md#transitioning-the-gossip) for +details on how to handle transitioning gossip topics for this upgrade. + +## Design rationale + +## Why is it proposer may send multiple inclusion lists? Why not just one per slot? + +Proposers may submit multiple inclusion lists, providing validators with plausible deniability and eliminating a data availability attack route. This concept stems from the "no free lunch IL design" which lets proposers send multiple ILs. The idea is that since only one IL is eventually chosen from many, thus its contents can't be relied upon for data availability. diff --git a/specs/_features/eip7547/validator.md b/specs/_features/eip7547/validator.md new file mode 100644 index 0000000000..c585f6410f --- /dev/null +++ b/specs/_features/eip7547/validator.md @@ -0,0 +1,159 @@ +# EIP-7547 -- Honest Validator + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Helpers](#helpers) + - [`GetInclusionListResponse`](#getinclusionlistresponse) +- [Protocols](#protocols) + - [`ExecutionEngine`](#executionengine) + - [`get_execution_inclusion_list`](#get_execution_inclusion_list) +- [Beacon chain responsibilities](#beacon-chain-responsibilities) + - [Inclusion list proposal](#inclusion-list-proposal) + - [Constructing the inclusion list](#constructing-the-inclusion-list) + - [Broadcast inclusion list](#broadcast-inclusion-list) + - [Block and sidecar proposal](#block-and-sidecar-proposal) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayload](#executionpayload) + - [`inclusion_list_summary`](#inclusion_list_summary) + + + + +## Introduction + +This document represents the changes to be made in the code of an "honest validator" to implement EIP-7547. + +## Prerequisites + +This document is an extension of the [Deneb -- Honest Validator](../../deneb/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 [EIP-7547](./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 + +### `GetInclusionListResponse` + +```python +class GetInclusionListResponse(Container): + inclusion_list_summary: InclusionListSummary + transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST] +``` + +## Protocols + +### `ExecutionEngine` + +*Note*: `get_execution_inclusion_list` function is added to the `ExecutionEngine` protocol for use as a validator. + +The body of this function is implementation dependent. +The Engine API may be used to implement it with an external execution engine. + +#### `get_execution_inclusion_list` + +Given the `parent_block_hash`, `get_execution_inclusion_list` returns `GetInclusionListResponse` with the most recent version of the inclusion list based on the parent block hash. + +```python +def get_execution_inclusion_list(self: ExecutionEngine, parent_block_hash: Root) -> GetInclusionListResponse: + """ + Return ``GetInclusionListResponse`` object. + """ + ... +``` + +## Beacon chain responsibilities + +All validator responsibilities remain unchanged other than those noted below. + +### Inclusion list proposal + +EIP7547 introduces forward inclusion list. The detail design is described in this [post](https://ethresear.ch/t/no-free-lunch-a-new-inclusion-list-design/16389). + +Proposer must construct and broadcast `SignedInclusionListTransactions` alongside the `SignedBeaconBlock`. +- Proposer for slot `N` submits `SignedBeaconBlock` which now contains their `InclusionListSummary` and broacast it alongside the `SignedInclusionListTransactions`. The slot `N+1` execution payload is checked against the summary. +- `Transactions` is list of transactions that the proposer wants to include in slot `N+1`. +- `Summary` is a list of the addresses sending those transactions and their gas limits. +- Proposer may send many `SignedInclusionListTransactions` each with valid transactions. + +#### Constructing the inclusion list + +To obtain an inclusion list, a block proposer building a block on top of a `state` must take the following actions: + +1. Retrieve `inclusion_list_response: GetInclusionListResponse` from execution layer by calling `ExecutionEngine.get_execution_inclusion_list(parent_block_hash)`. + +2. Call `build_inclusion_list` to build `InclusionList`. + +```python +def build_inclusion_list(state: BeaconState, inclusion_list_response: GetInclusionListResponse, + block_slot: Slot, privkey: int) -> InclusionList: + inclusion_list_transactions = inclusion_list_response.inclusion_list_transactions + signature = get_inclusion_list_transactions_signature(state, inclusion_list_transactions, block_slot, privkey) + signed_inclusion_list_transactions = SignedInclusionListTransactions(transactions=inclusion_list_transactions, signature=signature) + return InclusionList(summary=inclusion_list_reponse.summary, transactions=signed_inclusion_list_transactions) +``` + +In order to get inclusion list transactions signature, the proposer will call `get_inclusion_list_transactions_signature`. + +```python +def get_inclusion_list_transactions_signature(state: BeaconState, + inclusion_list_summary: InclusionListSummary, + block_slot: Slot, + privkey: int) -> BLSSignature: + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block_slot)) + signing_root = compute_signing_root(inclusion_list_summary, domain) + return bls.Sign(privkey, signing_root) +``` + +#### Broadcast inclusion list + +Finally, the proposer broadcasts `inclusion_list` along with the `SignedBeaconBlock` on the `beacon_block` pubsub topic. + +### Block and sidecar proposal + +#### Constructing the `BeaconBlockBody` + +##### ExecutionPayload + +##### `inclusion_list_summary` + +`prepare_execution_payload` is updated from the Deneb specs to provide the `inclusion_list_summary`. + +*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 `inclusion_list_summary`. + +```python +def prepare_execution_payload( + state: BeaconState, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + inclusion_list_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST], + 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), + inclusion_list_transactions=inclusion_list_transactions, # [New in EIP7547] + ) + 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/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index fc939ce097..41d4f50412 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -19,6 +19,7 @@ EIP6110 = SpecForkName('eip6110') EIP7002 = SpecForkName('eip7002') WHISK = SpecForkName('whisk') +EIP7547 = SpecForkName('eip7547') EIP7594 = SpecForkName('eip7594') # @@ -38,6 +39,7 @@ # Experimental patches EIP6110, EIP7002, + EIP7547, EIP7594, ) # The forks that have light client specs @@ -59,6 +61,7 @@ EIP6110: DENEB, WHISK: CAPELLA, EIP7002: CAPELLA, + EIP7547: DENEB, EIP7594: DENEB, }