diff --git a/beacon_chain/el/el_manager.nim b/beacon_chain/el/el_manager.nim index c88defa1ec..a11994b084 100644 --- a/beacon_chain/el/el_manager.nim +++ b/beacon_chain/el/el_manager.nim @@ -51,6 +51,14 @@ type # `Raising()` macro starts to support procedure arguments. future*: Future[void].Raising([CancelledError]) + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#modified-newpayloadrequest + NewPayloadRequest* = object + executionPayload*: ExecutionPayloadV3 + versioned_hashes*: seq[deneb.VersionedHash] + parent_beacon_block_root*: Eth2Digest + execution_requests*: seq[seq[byte]] + inclusion_list_transactions*: seq[bellatrix.Transaction] # [New in EIP-7805] + SomeEnginePayloadWithValue = BellatrixExecutionPayloadWithValue | GetPayloadV2Response | diff --git a/beacon_chain/spec/datatypes/focil.nim b/beacon_chain/spec/datatypes/focil.nim new file mode 100644 index 0000000000..1f80a75a06 --- /dev/null +++ b/beacon_chain/spec/datatypes/focil.nim @@ -0,0 +1,69 @@ +# beacon_chain +# Copyright (c) 2022-2025 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +# Types specific to Fulu (i.e. known to have changed across hard forks) - see +# `base` for types and guidelines common across forks + +# TODO Careful, not nil analysis is broken / incomplete and the semantics will +# likely change in future versions of the language: +# https://github.com/nim-lang/RFCs/issues/250 +{.experimental: "notnil".} + +import + std/[sequtils, typetraits], + "."/[phase0, base, electra], + chronicles, + chronos, + json_serialization, + ssz_serialization/[merkleization, proofs], + ssz_serialization/types as sszTypes, + ../digest, + kzg4844/[kzg, kzg_abi] + +from std/strutils import join +from stew/bitops2 import log2trunc +from stew/byteutils import to0xHex +from ./altair import + EpochParticipationFlags, InactivityScores, SyncAggregate, SyncCommittee, + TrustedSyncAggregate, SyncnetBits, num_active_participants +from ./bellatrix import BloomLogs, ExecutionAddress, Transaction +from ./capella import + ExecutionBranch, HistoricalSummary, SignedBLSToExecutionChange, + SignedBLSToExecutionChangeList, Withdrawal, EXECUTION_PAYLOAD_GINDEX +from ./deneb import Blobs, BlobsBundle, KzgCommitments, KzgProofs +from ./constants import DomainType + +export json_serialization, base + +const + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#domain-types + DOMAIN_INCLUSION_LIST_COMMITTEE* = DomainType([byte 0x0c, 0x00, 0x00, 0x00]) + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#preset + INCLUSION_LIST_COMMITTEE_SIZE* = 16'u64 + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/fork-choice.md#time-parameters + VIEW_FREEZE_DEADLINE* = (SECONDS_PER_SLOT * 2 div 3 + 1).seconds + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/p2p-interface.md#configuration + ATTESTATION_DEADLINE* = (SECONDS_PER_SLOT div 3).seconds + MAX_REQUEST_INCLUSION_LIST* = 16'u64 + MAX_BYTES_PER_INCLUSION_LIST* = 8192'u64 + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/validator.md#configuration + PROPOSER_INCLUSION_LIST_CUT_OFF = (SECONDS_PER_SLOT - 1).seconds + +type + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#inclusionlist + InclusionList* = object + slot*: Slot + validator_index*: ValidatorIndex + inclusion_list_committee_root: Eth2Digest + transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + + # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#signedinclusionlist + SignedInclusionList* = object + message*: InclusionList + signature*: ValidatorSig diff --git a/beacon_chain/spec/focil_helpers.nim b/beacon_chain/spec/focil_helpers.nim new file mode 100644 index 0000000000..3b967489d3 --- /dev/null +++ b/beacon_chain/spec/focil_helpers.nim @@ -0,0 +1,86 @@ +# beacon_chain +# Copyright (c) 2018-2025 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +# Uncategorized helper functions from the spec +import + std/[algorithm, sequtils], + results, + eth/p2p/discoveryv5/[node], + kzg4844/[kzg], + ssz_serialization/[ + proofs, + types], + ./crypto, + ./[helpers, digest, beacon_time, + validator], + ./datatypes/[fulu, focil] + +# https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#new-is_valid_inclusion_list_signature +func verify_inclusion_list_signature*( + state: ForkyBeaconState, + signed_inclusion_list: SignedInclusionList): bool = + ## Check if the `signed_inclusion_list` has a valid signature + let + message = signed_inclusion_list.message + pubkey = + state.validators[message.validator_index].pubkeyData + domain = get_domain(state, DOMAIN_INCLUSION_LIST_COMMITTEE, + message.slot.epoch()) + signing_root = + compute_signing_root(message, domain) + blsVerify(pubkey, signing_root.data, signature) + +# https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#new-get_inclusion_list_committee +func resolve_inclusion_list_committee*( + state: ForkyBeaconState, + slot: Slot): HashSet[ValidatorIndex] = + ## Return the inclusion list committee for the given slot + let + seed = get_seed(state, slot.epoch(), DOMAIN_INCLUSION_LIST_COMMITTEE) + indices = + get_active_validator_indices(state, epoch) + + start = (slot mod SLOTS_PER_EPOCH) * INCLUSION_LIST_COMMITTEE_SIZE + end_i = start + INCLUSION_LIST_COMMITTEE_SIZE + seq_len {.inject.} = indices.lenu64 + + var res: HashSet[ValidatorIndex] + for i in 0..