From e0fc1a7df7e821842dfb0730ac47bc22b3fef3c0 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Fri, 11 Jul 2025 09:46:34 +0700 Subject: [PATCH 01/13] add the p2p related constants --- beacon_chain/spec/datatypes/constants.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index 442d67c6ff..da3d9fee0f 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -87,3 +87,8 @@ const DEPOSIT_REQUEST_TYPE* = 0x00'u8 WITHDRAWAL_REQUEST_TYPE* = 0x01'u8 CONSOLIDATION_REQUEST_TYPE* = 0x02'u8 + + # https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#configuration + MAX_REQUEST_INCLUSION_LIST*: uint64 = 16 # 2**4 + MAX_BYTES_PER_INCLUSION_LIST*: uint64 = 8192 # 2**13 + INCLUSION_LIST_COMMITTEE_SIZE*: uint64 = 128 From 5783f86703db8148c913cd3f8490ee3c87f9618f Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Fri, 11 Jul 2025 13:00:05 +0700 Subject: [PATCH 02/13] add IL topic definitions --- beacon_chain/spec/network.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index 3a89bfda5d..44ac6ae281 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -16,12 +16,14 @@ export base const # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.10/specs/phase0/p2p-interface.md#topics-and-messages # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/capella/p2p-interface.md#topics-and-messages + # https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#topics-and-messages topicBeaconBlocksSuffix = "beacon_block/ssz_snappy" topicVoluntaryExitsSuffix = "voluntary_exit/ssz_snappy" topicProposerSlashingsSuffix = "proposer_slashing/ssz_snappy" topicAttesterSlashingsSuffix = "attester_slashing/ssz_snappy" topicAggregateAndProofsSuffix = "beacon_aggregate_and_proof/ssz_snappy" topicBlsToExecutionChangeSuffix = "bls_to_execution_change/ssz_snappy" + topicInclusionListSuffix = "inclusion_list/ssz_snappy" const # The spec now includes this as a bare uint64 as `RESP_TIMEOUT` @@ -68,6 +70,10 @@ func getAggregateAndProofsTopic*(forkDigest: ForkDigest): string = func getBlsToExecutionChangeTopic*(forkDigest: ForkDigest): string = eth2Prefix(forkDigest) & topicBlsToExecutionChangeSuffix +# https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#topics-and-messages +func getInclusionListTopic*(forkDigest: ForkDigest): string = + eth2Prefix(forkDigest) & topicInclusionListSuffix + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.2/specs/phase0/validator.md#broadcast-attestation func compute_subnet_for_attestation*( committees_per_slot: uint64, slot: Slot, committee_index: CommitteeIndex): From f5d06f9a96b4ecb19c4c7e74d5aac49841ba5bbd Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 12:48:46 +0700 Subject: [PATCH 03/13] cleanup and fix func naming --- beacon_chain/spec/focil_helpers.nim | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/beacon_chain/spec/focil_helpers.nim b/beacon_chain/spec/focil_helpers.nim index 3b967489d3..3d4b4d2e6c 100644 --- a/beacon_chain/spec/focil_helpers.nim +++ b/beacon_chain/spec/focil_helpers.nim @@ -22,7 +22,7 @@ import ./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*( +func is_valid_inclusion_list_signature*( state: ForkyBeaconState, signed_inclusion_list: SignedInclusionList): bool = ## Check if the `signed_inclusion_list` has a valid signature @@ -34,7 +34,7 @@ func verify_inclusion_list_signature*( message.slot.epoch()) signing_root = compute_signing_root(message, domain) - blsVerify(pubkey, signing_root.data, signature) + blsVerify(pubkey, signing_root.data, signed_inclusion_list.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*( @@ -44,7 +44,7 @@ func resolve_inclusion_list_committee*( let seed = get_seed(state, slot.epoch(), DOMAIN_INCLUSION_LIST_COMMITTEE) indices = - get_active_validator_indices(state, epoch) + get_active_validator_indices(state, slot.epoch()) start = (slot mod SLOTS_PER_EPOCH) * INCLUSION_LIST_COMMITTEE_SIZE end_i = start + INCLUSION_LIST_COMMITTEE_SIZE @@ -72,14 +72,11 @@ func get_inclusion_committee_assignment*( ## Returns None if no assignment is found. let next_epoch = Epoch(state.slot.epoch() + 1) - start_slot = epoch.start_slot() - doAssert epoch <= nextEpoch for epochSlot in epoch.slots(): let - slot = Slot(epochSlot + start_slot) - committee = resolve_inclusion_list_committee(state, slot) + committee = resolve_inclusion_list_committee(state, epochSlot) if validator_index in committee: return Opt.som(slot) From 7fdbdf28a4430da1a05b0d92047bb1326bea5ad1 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 12:49:43 +0700 Subject: [PATCH 04/13] make data field public --- beacon_chain/spec/datatypes/focil.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_chain/spec/datatypes/focil.nim b/beacon_chain/spec/datatypes/focil.nim index 1f80a75a06..d578a80a89 100644 --- a/beacon_chain/spec/datatypes/focil.nim +++ b/beacon_chain/spec/datatypes/focil.nim @@ -60,8 +60,8 @@ type InclusionList* = object slot*: Slot validator_index*: ValidatorIndex - inclusion_list_committee_root: Eth2Digest - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + 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 From c4afbad5ecc7e0a592dc4ecc935e2ae6f726adf9 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 12:50:13 +0700 Subject: [PATCH 05/13] add inclusion list signature utils --- beacon_chain/spec/signatures.nim | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/beacon_chain/spec/signatures.nim b/beacon_chain/spec/signatures.nim index 726c1b42ee..2c3c40eef2 100644 --- a/beacon_chain/spec/signatures.nim +++ b/beacon_chain/spec/signatures.nim @@ -17,7 +17,7 @@ ## functions. import - ./datatypes/[phase0, altair, bellatrix], ./helpers, ./eth2_merkleization + ./datatypes/[phase0, altair, bellatrix, focil], ./helpers, ./eth2_merkleization from ./datatypes/capella import BLSToExecutionChange, SignedBLSToExecutionChange @@ -424,3 +424,27 @@ proc verify_bls_to_execution_change_signature*( let signing_root = compute_bls_to_execution_change_signing_root( genesisFork, genesis_validators_root, msg.message) blsVerify(pubkey, signing_root.data, signature) + +# https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/validator.md#constructing-a-signed-inclusion-list +func compute_inclusion_list_signing_root*( + fork: Fork, genesis_validators_root: Eth2Digest, + message: InclusionList): Eth2Digest = + let domain = get_domain( + fork, DOMAIN_INCLUSION_LIST_COMMITTEE, message.slot.epoch(), + genesis_validators_root) + compute_signing_root(message, domain) + +func get_inclusion_list_signature*( + fork: Fork, genesis_validators_root: Eth2Digest, + message: InclusionList, privkey: ValidatorPrivKey): CookedSig = + let signing_root = compute_inclusion_list_signing_root( + fork, genesis_validators_root, message) + blsSign(privkey, signing_root.data) + +proc verify_inclusion_list_signature*( + fork: Fork, genesis_validators_root: Eth2Digest, + message: InclusionList, + pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool = + let signing_root = compute_inclusion_list_signing_root( + fork, genesis_validators_root, message) + blsVerify(pubkey, signing_root.data, signature) \ No newline at end of file From 9ef9e7fdbc385bdddd25265f56606689297ffc44 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 12:51:10 +0700 Subject: [PATCH 06/13] inclusion list batch sig --- beacon_chain/spec/signatures_batch.nim | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/beacon_chain/spec/signatures_batch.nim b/beacon_chain/spec/signatures_batch.nim index f62b9c0180..9337b33997 100644 --- a/beacon_chain/spec/signatures_batch.nim +++ b/beacon_chain/spec/signatures_batch.nim @@ -21,7 +21,7 @@ import bearssl/rand, # Internal "."/[helpers, beaconstate, forks, signatures], - "."/datatypes/[altair, bellatrix, phase0] + "."/datatypes/[altair, bellatrix, phase0, focil] export results, rand, altair, phase0, taskpools, signatures @@ -227,6 +227,16 @@ func bls_to_execution_change_signature_set*( SignatureSet.init(pubkey, signing_root, signature) +# https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/validator.md#constructing-a-signed-inclusion-list +func inclusion_list_signature_set*( + fork: Fork, genesis_validators_root: Eth2Digest, + message: InclusionList, + pubkey: CookedPubKey, signature: CookedSig): SignatureSet = + let signing_root = compute_inclusion_list_signing_root( + fork, genesis_validators_root, message) + + SignatureSet.init(pubkey, signing_root, signature) + proc collectProposerSignatureSet*( sigs: var seq[SignatureSet], blocks: openArray[ForkedSignedBeaconBlock], From ba157f0df45acbb1d00cd068e19a9fd5fb9af875 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 12:52:50 +0700 Subject: [PATCH 07/13] add inclusion list batch validation --- .../gossip_processing/batch_validation.nim | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/beacon_chain/gossip_processing/batch_validation.nim b/beacon_chain/gossip_processing/batch_validation.nim index bd700996da..78233ef2d9 100644 --- a/beacon_chain/gossip_processing/batch_validation.nim +++ b/beacon_chain/gossip_processing/batch_validation.nim @@ -14,7 +14,8 @@ import # Status chronicles, chronos, chronos/threadsync, ../spec/signatures_batch, - ../consensus_object_pools/[blockchain_dag, spec_cache] + ../consensus_object_pools/[blockchain_dag, spec_cache], + ../spec/datatypes/focil export signatures_batch, blockchain_dag @@ -577,3 +578,28 @@ proc scheduleBlsToExecutionChangeCheck*( pubkey, sig) ok((fut, sig)) + +proc scheduleInclusionListCheck*( + batchCrypto: ref BatchCrypto, + fork: Fork, + message: InclusionList, + pubkey: CookedPubKey, + signature: ValidatorSig): + Result[tuple[fut: FutureBatchResult, sig: CookedSig], cstring] = + ## Schedule crypto verification of an inclusion list signature + ## + ## The buffer is processed: + ## - when eager processing is enabled and the batch is full + ## - otherwise after 10ms (BatchAttAccumTime) + ## + ## This returns an error if crypto sanity checks failed + ## and a future with the deferred check otherwise. + + let + sig = signature.load().valueOr: + return err("InclusionList: cannot load signature") + fut = batchCrypto.verifySoon("scheduleInclusionListCheck"): + inclusion_list_signature_set( + fork, batchCrypto[].genesis_validators_root, message, pubkey, sig) + + ok((fut, sig)) From a5b4ecc6811d3e93e9f6e44ad688588046851309 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 13:08:24 +0700 Subject: [PATCH 08/13] add inclusion list gossip validation --- .../gossip_processing/gossip_validation.nim | 85 ++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/beacon_chain/gossip_processing/gossip_validation.nim b/beacon_chain/gossip_processing/gossip_validation.nim index e0f3e7e851..5208964e24 100644 --- a/beacon_chain/gossip_processing/gossip_validation.nim +++ b/beacon_chain/gossip_processing/gossip_validation.nim @@ -16,11 +16,11 @@ import # Internals ../spec/[ beaconstate, state_transition_block, forks, - helpers, network, signatures, peerdas_helpers], + helpers, network, signatures, peerdas_helpers, focil_helpers], ../consensus_object_pools/[ attestation_pool, blockchain_dag, blob_quarantine, block_quarantine, data_column_quarantine, spec_cache, light_client_pool, sync_committee_msg_pool, - validator_change_pool], + validator_change_pool, inclusion_list_pool], ".."/[beacon_clock], ./batch_validation @@ -1893,3 +1893,84 @@ proc validateLightClientOptimisticUpdate*( pool.latestForwardedOptimisticSlot = attested_slot ok() + +# https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#global-topics +proc validateInclusionList*( + pool: var InclusionListPool, dag: ChainDAGRef, + batchCrypto: ref BatchCrypto, + signed_inclusion_list: SignedInclusionList, + wallTime: BeaconTime, checkSignature: bool): + Future[Result[CookedSig, ValidationError]] {.async: (raises: [CancelledError]).} = + ## Validate a signed inclusion list according to the EIP-7805 specification + + template message: untyped = signed_inclusion_list.message + + # [REJECT] The size of message.transactions is within upperbound MAX_BYTES_PER_INCLUSION_LIST. + var totalSize: uint64 = 0 + for transaction in message.transactions: + totalSize += uint64(transaction.len) + if totalSize > MAX_BYTES_PER_INCLUSION_LIST: + return dag.checkedReject("InclusionList: transactions size exceeds MAX_BYTES_PER_INCLUSION_LIST") + + # [REJECT] The slot message.slot is equal to the previous or current slot. + let currentSlot = wallTime.slotOrZero + if not (message.slot == currentSlot or message.slot == currentSlot - 1): + return dag.checkedReject("InclusionList: slot must be current or previous slot") + + # [IGNORE] The slot message.slot is equal to the current slot, or it is equal to the previous slot and the current time is less than ATTESTATION_DEADLINE seconds into the slot. + if message.slot == currentSlot - 1: + let slotStartTime = message.slot.start_time() + let currentTime = wallTime + if currentTime >= slotStartTime + ATTESTATION_DEADLINE: + return errIgnore("InclusionList: previous slot inclusion list received after deadline") + + # [IGNORE] The inclusion_list_committee for slot message.slot on the current branch corresponds to message.inclusion_list_committee_root, as determined by hash_tree_root(inclusion_list_committee) == message.inclusion_list_committee_root. + withState(dag.headState): + let committee = resolve_inclusion_list_committee(forkyState.data, message.slot) + # Note: We need to convert the HashSet to a sequence for hash_tree_root + var committeeSeq: seq[ValidatorIndex] + for validator in committee: + committeeSeq.add(validator) + let committeeRoot = hash_tree_root(committeeSeq) + if committeeRoot != message.inclusion_list_committee_root: + return errIgnore("InclusionList: inclusion list committee root mismatch") + + # [REJECT] The validator index message.validator_index is within the inclusion_list_committee corresponding to message.inclusion_list_committee_root. + withState(dag.headState): + let committee = resolve_inclusion_list_committee(forkyState.data, message.slot) + if message.validator_index notin committee: + return dag.checkedReject("InclusionList: validator not in inclusion list committee") + + # [IGNORE] The message is either the first or second valid message received from the validator with index message.validator_index. + if pool.isSeen(signed_inclusion_list): + return errIgnore("InclusionList: already received inclusion list from this validator") + + # [REJECT] The signature of inclusion_list.signature is valid with respect to the validator index. + let sig = + if checkSignature: + withState(dag.headState): + let pubkey = forkyState.data.validators[message.validator_index].pubkeyData + let deferredCrypto = batchCrypto.scheduleInclusionListCheck( + dag.forkAtEpoch(message.slot.epoch), + message, pubkey, signed_inclusion_list.signature) + if deferredCrypto.isErr(): + return dag.checkedReject(deferredCrypto.error) + + let (cryptoFut, sig) = deferredCrypto.get() + # Await the crypto check + let x = (await cryptoFut) + case x + of BatchResult.Invalid: + return dag.checkedReject("InclusionList: invalid signature") + of BatchResult.Timeout: + return errIgnore("InclusionList: timeout checking signature") + of BatchResult.Valid: + sig # keep going only in this case + else: + signed_inclusion_list.signature.load().valueOr: + return dag.checkedReject("InclusionList: unable to load signature") + + # Add the inclusion list to the pool + pool.addMessage(signed_inclusion_list) + + ok(sig) \ No newline at end of file From bd811e6f2a49edd8a301c9fb98a6ce329338a8f8 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sat, 12 Jul 2025 13:17:42 +0700 Subject: [PATCH 09/13] add draft inclusion list pool --- .../inclusion_list_pool.nim | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 beacon_chain/consensus_object_pools/inclusion_list_pool.nim diff --git a/beacon_chain/consensus_object_pools/inclusion_list_pool.nim b/beacon_chain/consensus_object_pools/inclusion_list_pool.nim new file mode 100644 index 0000000000..9263078ac7 --- /dev/null +++ b/beacon_chain/consensus_object_pools/inclusion_list_pool.nim @@ -0,0 +1,87 @@ +# beacon_chain +# Copyright (c) 2024-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: [].} + +import + # Standard libraries + std/[deques, sets], + # Internal + ../spec/datatypes/[base, focil], + ../spec/[helpers, state_transition_block, focil_helpers], + "."/[blockchain_dag] + +export base, deques, blockchain_dag, focil + +const + INCLUSION_LISTS_BOUND = 1024'u64 # Reasonable bound for inclusion lists + +type + OnInclusionListCallback = + proc(data: SignedInclusionList) {.gcsafe, raises: [].} + + InclusionListPool* = object + ## The inclusion list pool tracks signed inclusion lists that could be + ## added to a proposed block. + + inclusion_lists*: Deque[SignedInclusionList] ## \ + ## Not a function of chain DAG branch; just used as a FIFO queue for blocks + + prior_seen_inclusion_list_validators: HashSet[uint64] ## \ + ## Records validator indices that have already submitted inclusion lists + ## to prevent duplicate processing + + dag*: ChainDAGRef + onInclusionListReceived*: OnInclusionListCallback + +func init*(T: type InclusionListPool, dag: ChainDAGRef, + onInclusionList: OnInclusionListCallback = nil): T = + ## Initialize an InclusionListPool from the dag `headState` + T( + inclusion_lists: + initDeque[SignedInclusionList](initialSize = INCLUSION_LISTS_BOUND.int), + dag: dag, + onInclusionListReceived: onInclusionList) + +func addInclusionListMessage( + subpool: var Deque[SignedInclusionList], + seenpool: var HashSet[uint64], + inclusionList: SignedInclusionList, + bound: static[uint64]) = + ## Add an inclusion list message to the pool, maintaining bounds + while subpool.lenu64 >= bound: + seenpool.excl subpool.popFirst().message.validator_index.uint64 + + subpool.addLast(inclusionList) + doAssert subpool.lenu64 <= bound + +func isSeen*(pool: InclusionListPool, msg: SignedInclusionList): bool = + ## Check if we've already seen an inclusion list from this validator + msg.message.validator_index.uint64 in pool.prior_seen_inclusion_list_validators + +func addMessage*(pool: var InclusionListPool, msg: SignedInclusionList) = + ## Add an inclusion list message to the pool + pool.prior_seen_inclusion_list_validators.incl( + msg.message.validator_index.uint64) + + pool.inclusion_lists.addInclusionListMessage( + pool.prior_seen_inclusion_list_validators, msg, INCLUSION_LISTS_BOUND) + + # Send notification about new inclusion list via callback + if not(isNil(pool.onInclusionListReceived)): + pool.onInclusionListReceived(msg) + +func getInclusionLists*(pool: InclusionListPool): seq[SignedInclusionList] = + ## Get all inclusion lists in the pool + result = newSeq[SignedInclusionList](pool.inclusion_lists.len) + for i, inclusionList in pool.inclusion_lists: + result[i] = inclusionList + +func clear*(pool: var InclusionListPool) = + ## Clear all inclusion lists from the pool + pool.inclusion_lists.clear() + pool.prior_seen_inclusion_list_validators.clear() \ No newline at end of file From e61b4e316ef72a180f00751cc4eb62f1e49eda1d Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Sun, 13 Jul 2025 19:05:23 +0700 Subject: [PATCH 10/13] fix the seconds typecast error --- beacon_chain/spec/datatypes/focil.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beacon_chain/spec/datatypes/focil.nim b/beacon_chain/spec/datatypes/focil.nim index d578a80a89..920221566a 100644 --- a/beacon_chain/spec/datatypes/focil.nim +++ b/beacon_chain/spec/datatypes/focil.nim @@ -47,13 +47,13 @@ const # 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 + VIEW_FREEZE_DEADLINE* = chronos.seconds((SECONDS_PER_SLOT * 2 div 3 + 1).int64) # 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 + ATTESTATION_DEADLINE* = chronos.seconds((SECONDS_PER_SLOT div 3).int64) 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 + PROPOSER_INCLUSION_LIST_CUT_OFF = chronos.seconds((SECONDS_PER_SLOT - 1).int64) type # https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.2/specs/_features/eip7805/beacon-chain.md#inclusionlist From bef8a8f485286fab1dfc46ad72825816e56558f6 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Mon, 14 Jul 2025 00:31:54 +0700 Subject: [PATCH 11/13] remove unused imports and fix type defn --- beacon_chain/spec/datatypes/constants.nim | 1 - beacon_chain/spec/datatypes/focil.nim | 7 +------ beacon_chain/spec/focil_helpers.nim | 6 +++--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index da3d9fee0f..61b6b0464f 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -90,5 +90,4 @@ const # https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#configuration MAX_REQUEST_INCLUSION_LIST*: uint64 = 16 # 2**4 - MAX_BYTES_PER_INCLUSION_LIST*: uint64 = 8192 # 2**13 INCLUSION_LIST_COMMITTEE_SIZE*: uint64 = 128 diff --git a/beacon_chain/spec/datatypes/focil.nim b/beacon_chain/spec/datatypes/focil.nim index 920221566a..5074cb3202 100644 --- a/beacon_chain/spec/datatypes/focil.nim +++ b/beacon_chain/spec/datatypes/focil.nim @@ -16,9 +16,7 @@ {.experimental: "notnil".} import - std/[sequtils, typetraits], "."/[phase0, base, electra], - chronicles, chronos, json_serialization, ssz_serialization/[merkleization, proofs], @@ -26,9 +24,6 @@ import ../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 @@ -59,7 +54,7 @@ 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 + validator_index*: uint64 inclusion_list_committee_root*: Eth2Digest transactions*: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] diff --git a/beacon_chain/spec/focil_helpers.nim b/beacon_chain/spec/focil_helpers.nim index 3d4b4d2e6c..f7e0e71057 100644 --- a/beacon_chain/spec/focil_helpers.nim +++ b/beacon_chain/spec/focil_helpers.nim @@ -9,7 +9,7 @@ # Uncategorized helper functions from the spec import - std/[algorithm, sequtils], + std/[algorithm], results, eth/p2p/discoveryv5/[node], kzg4844/[kzg], @@ -74,9 +74,9 @@ func get_inclusion_committee_assignment*( next_epoch = Epoch(state.slot.epoch() + 1) doAssert epoch <= nextEpoch - for epochSlot in epoch.slots(): + for slot in epoch.slots(): let - committee = resolve_inclusion_list_committee(state, epochSlot) + committee = resolve_inclusion_list_committee(state, slot) if validator_index in committee: return Opt.som(slot) From 080adc515322ee81121815733151a184a07c7e7c Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Mon, 14 Jul 2025 00:33:01 +0700 Subject: [PATCH 12/13] use the correct function type --- .../consensus_object_pools/inclusion_list_pool.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/beacon_chain/consensus_object_pools/inclusion_list_pool.nim b/beacon_chain/consensus_object_pools/inclusion_list_pool.nim index 9263078ac7..f43c497244 100644 --- a/beacon_chain/consensus_object_pools/inclusion_list_pool.nim +++ b/beacon_chain/consensus_object_pools/inclusion_list_pool.nim @@ -12,7 +12,7 @@ import std/[deques, sets], # Internal ../spec/datatypes/[base, focil], - ../spec/[helpers, state_transition_block, focil_helpers], + ../spec/[helpers, state_transition_block], "."/[blockchain_dag] export base, deques, blockchain_dag, focil @@ -63,13 +63,13 @@ func isSeen*(pool: InclusionListPool, msg: SignedInclusionList): bool = ## Check if we've already seen an inclusion list from this validator msg.message.validator_index.uint64 in pool.prior_seen_inclusion_list_validators -func addMessage*(pool: var InclusionListPool, msg: SignedInclusionList) = +proc addMessage*(pool: var InclusionListPool, msg: SignedInclusionList) = ## Add an inclusion list message to the pool pool.prior_seen_inclusion_list_validators.incl( msg.message.validator_index.uint64) - pool.inclusion_lists.addInclusionListMessage( - pool.prior_seen_inclusion_list_validators, msg, INCLUSION_LISTS_BOUND) + addInclusionListMessage( + pool.inclusion_lists, pool.prior_seen_inclusion_list_validators, msg, INCLUSION_LISTS_BOUND) # Send notification about new inclusion list via callback if not(isNil(pool.onInclusionListReceived)): From 1b7293b9c4d620d1b7209cb150ee886f0ca3c5a7 Mon Sep 17 00:00:00 2001 From: h3lio5 Date: Mon, 14 Jul 2025 20:04:25 +0700 Subject: [PATCH 13/13] fix ssz and sig issues --- .../gossip_processing/gossip_validation.nim | 16 ++++++++++------ beacon_chain/spec/datatypes/constants.nim | 1 - beacon_chain/spec/focil_helpers.nim | 8 ++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/beacon_chain/gossip_processing/gossip_validation.nim b/beacon_chain/gossip_processing/gossip_validation.nim index 5208964e24..9f98b7924b 100644 --- a/beacon_chain/gossip_processing/gossip_validation.nim +++ b/beacon_chain/gossip_processing/gossip_validation.nim @@ -13,9 +13,10 @@ import results, kzg4844/[kzg, kzg_abi], stew/byteutils, + ssz_serialization/types as sszTypes, # Internals ../spec/[ - beaconstate, state_transition_block, forks, + beaconstate, state_transition_block, forks, datatypes/focil, helpers, network, signatures, peerdas_helpers, focil_helpers], ../consensus_object_pools/[ attestation_pool, blockchain_dag, blob_quarantine, block_quarantine, @@ -1919,7 +1920,7 @@ proc validateInclusionList*( # [IGNORE] The slot message.slot is equal to the current slot, or it is equal to the previous slot and the current time is less than ATTESTATION_DEADLINE seconds into the slot. if message.slot == currentSlot - 1: - let slotStartTime = message.slot.start_time() + let slotStartTime = message.slot.start_beacon_time() let currentTime = wallTime if currentTime >= slotStartTime + ATTESTATION_DEADLINE: return errIgnore("InclusionList: previous slot inclusion list received after deadline") @@ -1928,10 +1929,11 @@ proc validateInclusionList*( withState(dag.headState): let committee = resolve_inclusion_list_committee(forkyState.data, message.slot) # Note: We need to convert the HashSet to a sequence for hash_tree_root - var committeeSeq: seq[ValidatorIndex] + var committeeList: List[uint64, Limit INCLUSION_LIST_COMMITTEE_SIZE] for validator in committee: - committeeSeq.add(validator) - let committeeRoot = hash_tree_root(committeeSeq) + if not committeeList.add(validator): + raiseAssert "Committee list overflowed its maximum size" + let committeeRoot = hash_tree_root(committeeList) if committeeRoot != message.inclusion_list_committee_root: return errIgnore("InclusionList: inclusion list committee root mismatch") @@ -1949,7 +1951,9 @@ proc validateInclusionList*( let sig = if checkSignature: withState(dag.headState): - let pubkey = forkyState.data.validators[message.validator_index].pubkeyData + let + pubkey = dag.validatorKey(message.validator_index).valueOr: + return dag.checkedReject("InclusionList: invalid validator index") let deferredCrypto = batchCrypto.scheduleInclusionListCheck( dag.forkAtEpoch(message.slot.epoch), message, pubkey, signed_inclusion_list.signature) diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index 61b6b0464f..4298cc7e11 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -90,4 +90,3 @@ const # https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7805/p2p-interface.md#configuration MAX_REQUEST_INCLUSION_LIST*: uint64 = 16 # 2**4 - INCLUSION_LIST_COMMITTEE_SIZE*: uint64 = 128 diff --git a/beacon_chain/spec/focil_helpers.nim b/beacon_chain/spec/focil_helpers.nim index f7e0e71057..8fea319537 100644 --- a/beacon_chain/spec/focil_helpers.nim +++ b/beacon_chain/spec/focil_helpers.nim @@ -39,7 +39,7 @@ func is_valid_inclusion_list_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] = + slot: Slot): HashSet[uint64] = ## Return the inclusion list committee for the given slot let seed = get_seed(state, slot.epoch(), DOMAIN_INCLUSION_LIST_COMMITTEE) @@ -50,15 +50,15 @@ func resolve_inclusion_list_committee*( end_i = start + INCLUSION_LIST_COMMITTEE_SIZE seq_len {.inject.} = indices.lenu64 - var res: HashSet[ValidatorIndex] + var res: HashSet[uint64] for i in 0..