2020-07-30 19:18:17 +00:00
# beacon_chain
2024-01-06 14:26:56 +00:00
# Copyright (c) 2018-2024 Status Research & Development GmbH
2020-07-30 19:18:17 +00:00
# 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.
2023-01-20 14:14:37 +00:00
{. push raises : [ ] . }
2020-11-27 22:16:13 +00:00
2020-07-30 19:18:17 +00:00
import
2021-10-20 11:36:38 +00:00
std / sequtils ,
2024-01-16 22:37:14 +00:00
results ,
2020-10-22 10:53:33 +00:00
chronicles ,
2020-08-06 19:48:47 +00:00
.. / extras ,
2022-01-08 23:28:49 +00:00
.. / spec / [ beaconstate , helpers , network , signatures , validator ] ,
2021-08-12 13:08:20 +00:00
.. / spec / datatypes / base ,
. / block_pools_types , blockchain_dag
2024-05-14 11:51:06 +00:00
debugComment " probably just need Electra shortLog here "
2024-04-22 09:00:38 +00:00
import .. / spec / forks # prune this, it's for electra attestation logging
2021-08-12 13:08:20 +00:00
export
2022-01-08 23:28:49 +00:00
base , extras , block_pools_types , results
2020-07-30 19:18:17 +00:00
2022-07-06 10:33:02 +00:00
logScope : topics = " spec_cache "
2020-07-30 19:18:17 +00:00
# Spec functions implemented based on cached values instead of the full state
2022-08-18 18:07:01 +00:00
func count_active_validators * ( shufflingRef : ShufflingRef ) : uint64 =
shufflingRef . shuffled_active_validator_indices . lenu64
2020-07-30 19:18:17 +00:00
2024-04-17 03:51:16 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#get_committee_count_per_slot
2022-08-18 18:07:01 +00:00
func get_committee_count_per_slot * ( shufflingRef : ShufflingRef ) : uint64 =
get_committee_count_per_slot ( count_active_validators ( shufflingRef ) )
2020-07-30 19:18:17 +00:00
2022-08-18 18:07:01 +00:00
iterator get_committee_indices * ( shufflingRef : ShufflingRef ) : CommitteeIndex =
let committees_per_slot = get_committee_count_per_slot ( shufflingRef )
2022-01-08 23:28:49 +00:00
for committee_index in get_committee_indices ( committees_per_slot ) :
yield committee_index
2022-08-18 18:07:01 +00:00
func get_committee_index * ( shufflingRef : ShufflingRef , index : uint64 ) :
2022-01-08 23:28:49 +00:00
Result [ CommitteeIndex , cstring ] =
2022-08-18 18:07:01 +00:00
check_attestation_index ( index , get_committee_count_per_slot ( shufflingRef ) )
2021-05-10 07:13:36 +00:00
2024-01-20 11:19:47 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_beacon_committee
2020-10-22 10:53:33 +00:00
iterator get_beacon_committee * (
2022-08-18 18:07:01 +00:00
shufflingRef : ShufflingRef , slot : Slot , committee_index : CommitteeIndex ) :
2022-01-08 23:28:49 +00:00
( int , ValidatorIndex ) =
2021-10-14 06:30:21 +00:00
## Return the beacon committee at ``slot`` for ``index``.
2022-08-18 18:07:01 +00:00
doAssert slot . epoch = = shufflingRef . epoch
let committees_per_slot = get_committee_count_per_slot ( shufflingRef )
2022-01-08 23:28:49 +00:00
for index_in_committee , idx in compute_committee (
2022-08-18 18:07:01 +00:00
shufflingRef . shuffled_active_validator_indices ,
2022-01-08 23:28:49 +00:00
( slot mod SLOTS_PER_EPOCH ) * committees_per_slot + committee_index . asUInt64 ,
2020-10-22 10:53:33 +00:00
committees_per_slot * SLOTS_PER_EPOCH
2022-01-08 23:28:49 +00:00
) : yield ( index_in_committee , idx )
2020-10-22 10:53:33 +00:00
2024-04-17 03:51:16 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#get_beacon_committee
2020-07-30 19:18:17 +00:00
func get_beacon_committee * (
2022-08-18 18:07:01 +00:00
shufflingRef : ShufflingRef , slot : Slot , committee_index : CommitteeIndex ) :
2022-01-08 23:28:49 +00:00
seq [ ValidatorIndex ] =
2021-10-14 06:30:21 +00:00
## Return the beacon committee at ``slot`` for ``index``.
2022-08-18 18:07:01 +00:00
doAssert slot . epoch = = shufflingRef . epoch
let committees_per_slot = get_committee_count_per_slot ( shufflingRef )
2020-07-30 19:18:17 +00:00
compute_committee (
2022-08-18 18:07:01 +00:00
shufflingRef . shuffled_active_validator_indices ,
2022-01-08 23:28:49 +00:00
( slot mod SLOTS_PER_EPOCH ) * committees_per_slot + committee_index . asUInt64 ,
2020-07-30 19:18:17 +00:00
committees_per_slot * SLOTS_PER_EPOCH
)
2024-01-20 11:19:47 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_beacon_committee
2020-10-22 10:53:33 +00:00
func get_beacon_committee_len * (
2022-08-18 18:07:01 +00:00
shufflingRef : ShufflingRef , slot : Slot , committee_index : CommitteeIndex ) : uint64 =
2021-10-14 06:30:21 +00:00
## Return the number of members in the beacon committee at ``slot`` for ``index``.
2022-08-18 18:07:01 +00:00
doAssert slot . epoch = = shufflingRef . epoch
let committees_per_slot = get_committee_count_per_slot ( shufflingRef )
2020-10-22 10:53:33 +00:00
compute_committee_len (
2022-08-18 18:07:01 +00:00
count_active_validators ( shufflingRef ) ,
2022-01-08 23:28:49 +00:00
( slot mod SLOTS_PER_EPOCH ) * committees_per_slot + committee_index . asUInt64 ,
2020-10-22 10:53:33 +00:00
committees_per_slot * SLOTS_PER_EPOCH
)
2024-01-20 11:19:47 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_attesting_indices
2023-11-20 14:42:29 +00:00
func compatible_with_shuffling * (
2024-04-22 09:00:38 +00:00
bits : CommitteeValidatorsBits | ElectraCommitteeValidatorsBits ,
2023-11-20 14:42:29 +00:00
shufflingRef : ShufflingRef ,
slot : Slot ,
committee_index : CommitteeIndex ) : bool =
bits . lenu64 = = get_beacon_committee_len ( shufflingRef , slot , committee_index )
2022-08-18 18:07:01 +00:00
iterator get_attesting_indices * ( shufflingRef : ShufflingRef ,
2022-01-08 23:28:49 +00:00
slot : Slot ,
committee_index : CommitteeIndex ,
2024-04-28 00:52:14 +00:00
bits : CommitteeValidatorsBits ) :
2020-10-22 10:53:33 +00:00
ValidatorIndex =
2023-11-20 14:42:29 +00:00
if not bits . compatible_with_shuffling ( shufflingRef , slot , committee_index ) :
2020-10-22 10:53:33 +00:00
trace " get_attesting_indices: inconsistent aggregation and committee length "
else :
2022-01-08 23:28:49 +00:00
for index_in_committee , validator_index in get_beacon_committee (
2022-08-18 18:07:01 +00:00
shufflingRef , slot , committee_index ) :
2022-01-08 23:28:49 +00:00
if bits [ index_in_committee ] :
yield validator_index
2020-10-22 10:53:33 +00:00
2024-04-28 00:52:14 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#modified-get_attesting_indices
iterator get_attesting_indices * ( shufflingRef : ShufflingRef ,
slot : Slot ,
2024-05-14 16:01:26 +00:00
committee_bits : AttestationCommitteeBits ,
aggregation_bits : ElectraCommitteeValidatorsBits ) :
2024-04-28 00:52:14 +00:00
ValidatorIndex =
2024-05-14 16:01:26 +00:00
debugRaiseAssert " compatible with shuffling? needs checking "
#if not aggregation_bits.compatible_with_shuffling(shufflingRef, slot, committee_index):
if false :
trace " get_attesting_indices: inconsistent aggregation and committee length "
else :
debugComment " replace this implementation with actual iterator, after checking on conditions re repeat vals, ordering, etc; this is almost direct transcription of spec link algorithm in one of the places it doesn ' t make sense "
## Return the set of attesting indices corresponding to ``aggregation_bits``
## and ``committee_bits``.
var output : HashSet [ ValidatorIndex ]
let committee_indices = toSeq ( committee_bits . oneIndices )
var committee_offset = 0
for index in committee_indices :
let committee = get_beacon_committee ( shufflingRef , slot , index . CommitteeIndex )
var committee_attesters : HashSet [ ValidatorIndex ]
for i , index in committee :
if aggregation_bits [ committee_offset + i ] :
committee_attesters . incl index
output . incl committee_attesters
committee_offset + = len ( committee )
for validatorIndex in output :
yield validatorIndex
2024-04-28 00:52:14 +00:00
2022-07-06 10:33:02 +00:00
iterator get_attesting_indices * (
2024-05-14 16:01:26 +00:00
dag : ChainDAGRef , attestation : phase0 . TrustedAttestation ) : ValidatorIndex =
2022-07-06 10:33:02 +00:00
block : # `return` is not allowed in an inline iterator
let
slot =
check_attestation_slot_target ( attestation . data ) . valueOr :
2022-08-30 02:59:42 +00:00
warn " Invalid attestation slot in trusted attestation " ,
2022-09-19 19:50:19 +00:00
attestation = shortLog ( attestation )
2022-07-13 13:48:09 +00:00
doAssert strictVerification notin dag . updateFlags
2022-07-06 10:33:02 +00:00
break
blck =
dag . getBlockRef ( attestation . data . beacon_block_root ) . valueOr :
2022-08-30 02:59:42 +00:00
# Attestation block unknown - this is fairly common because we
# discard alternative histories on restart
2022-09-27 16:56:08 +00:00
debug " Pruned block in trusted attestation " ,
attestation = shortLog ( attestation )
2022-07-06 10:33:02 +00:00
break
target =
blck . atCheckpoint ( attestation . data . target ) . valueOr :
2022-09-27 16:56:08 +00:00
# This may happen when there's no block at the epoch boundary slot
# leading to the case where the attestation block root is the
# finalized head (exists as BlockRef) but its target vote has
# already been pruned
notice " Pruned target in trusted attestation " ,
2022-08-30 02:59:42 +00:00
blck = shortLog ( blck ) ,
2022-09-19 19:50:19 +00:00
attestation = shortLog ( attestation )
2022-07-13 13:48:09 +00:00
doAssert strictVerification notin dag . updateFlags
2022-07-06 10:33:02 +00:00
break
2022-08-18 18:07:01 +00:00
shufflingRef =
dag . getShufflingRef ( target . blck , target . slot . epoch , false ) . valueOr :
2022-08-30 02:59:42 +00:00
warn " Attestation shuffling not found " ,
blck = shortLog ( blck ) ,
2022-09-19 19:50:19 +00:00
attestation = shortLog ( attestation )
2022-08-30 02:59:42 +00:00
2022-07-13 13:48:09 +00:00
doAssert strictVerification notin dag . updateFlags
2022-07-06 10:33:02 +00:00
break
2022-08-18 18:07:01 +00:00
committeesPerSlot = get_committee_count_per_slot ( shufflingRef )
2022-07-06 10:33:02 +00:00
committeeIndex =
CommitteeIndex . init ( attestation . data . index , committeesPerSlot ) . valueOr :
2022-08-30 02:59:42 +00:00
warn " Unexpected committee index in trusted attestation " ,
blck = shortLog ( blck ) ,
2022-09-19 19:50:19 +00:00
attestation = shortLog ( attestation )
2022-08-30 02:59:42 +00:00
2022-07-13 13:48:09 +00:00
doAssert strictVerification notin dag . updateFlags
2022-07-06 10:33:02 +00:00
break
for validator in get_attesting_indices (
2022-08-18 18:07:01 +00:00
shufflingRef , slot , committeeIndex , attestation . aggregation_bits ) :
2022-07-06 10:33:02 +00:00
yield validator
2024-05-14 16:01:26 +00:00
iterator get_attesting_indices * (
dag : ChainDAGRef , attestation : electra . TrustedAttestation ) : ValidatorIndex =
debugRaiseAssert " bad duplication, mostly to avoid the get_attesting_index call from potentially getting screwed up in deployment version "
block : # `return` is not allowed in an inline iterator
let
slot =
check_attestation_slot_target ( attestation . data ) . valueOr :
warn " Invalid attestation slot in trusted attestation " ,
attestation = shortLog ( attestation )
doAssert strictVerification notin dag . updateFlags
break
blck =
dag . getBlockRef ( attestation . data . beacon_block_root ) . valueOr :
# Attestation block unknown - this is fairly common because we
# discard alternative histories on restart
debug " Pruned block in trusted attestation " ,
attestation = shortLog ( attestation )
break
target =
blck . atCheckpoint ( attestation . data . target ) . valueOr :
# This may happen when there's no block at the epoch boundary slot
# leading to the case where the attestation block root is the
# finalized head (exists as BlockRef) but its target vote has
# already been pruned
notice " Pruned target in trusted attestation " ,
blck = shortLog ( blck ) ,
attestation = shortLog ( attestation )
doAssert strictVerification notin dag . updateFlags
break
shufflingRef =
dag . getShufflingRef ( target . blck , target . slot . epoch , false ) . valueOr :
warn " Attestation shuffling not found " ,
blck = shortLog ( blck ) ,
attestation = shortLog ( attestation )
doAssert strictVerification notin dag . updateFlags
break
for validator in get_attesting_indices (
shufflingRef , slot , attestation . committee_bits , attestation . aggregation_bits ) :
yield validator
2022-08-18 18:07:01 +00:00
func get_attesting_indices_one * ( shufflingRef : ShufflingRef ,
2022-01-08 23:28:49 +00:00
slot : Slot ,
committee_index : CommitteeIndex ,
2021-04-26 20:39:44 +00:00
bits : CommitteeValidatorsBits ) :
Option [ ValidatorIndex ] =
# A variation on get_attesting_indices that returns the validator index only
# if only one validator index is set
2022-01-08 23:28:49 +00:00
var res = none ( ValidatorIndex )
for validator_index in get_attesting_indices (
2022-08-18 18:07:01 +00:00
shufflingRef , slot , committee_index , bits ) :
2022-01-08 23:28:49 +00:00
if res . isSome ( ) : return none ( ValidatorIndex )
res = some ( validator_index )
res
2021-04-26 20:39:44 +00:00
2024-05-14 16:01:26 +00:00
func get_attesting_indices_one * ( shufflingRef : ShufflingRef ,
slot : Slot ,
committee_indices : AttestationCommitteeBits ,
aggregation_bits : ElectraCommitteeValidatorsBits ) :
Option [ ValidatorIndex ] =
# A variation on get_attesting_indices that returns the validator index only
# if only one validator index is set
var res = none ( ValidatorIndex )
for validator_index in get_attesting_indices (
shufflingRef , slot , committee_indices , aggregation_bits ) :
if res . isSome ( ) : return none ( ValidatorIndex )
res = some ( validator_index )
res
2024-01-20 11:19:47 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_attesting_indices
2022-08-18 18:07:01 +00:00
func get_attesting_indices * ( shufflingRef : ShufflingRef ,
2022-01-08 23:28:49 +00:00
slot : Slot ,
committee_index : CommitteeIndex ,
2020-07-30 19:18:17 +00:00
bits : CommitteeValidatorsBits ) :
2021-02-08 07:27:30 +00:00
seq [ ValidatorIndex ] =
2024-05-14 16:01:26 +00:00
for idx in get_attesting_indices ( shufflingRef , slot , committee_index , bits ) :
result . add ( idx )
func get_attesting_indices * ( shufflingRef : ShufflingRef ,
slot : Slot ,
committee_index : CommitteeIndex ,
bits : ElectraCommitteeValidatorsBits ) :
seq [ ValidatorIndex ] =
2022-08-18 18:07:01 +00:00
for idx in get_attesting_indices ( shufflingRef , slot , committee_index , bits ) :
2021-02-08 07:27:30 +00:00
result . add ( idx )
2020-07-30 19:18:17 +00:00
2020-08-10 13:21:31 +00:00
func makeAttestationData * (
epochRef : EpochRef , bs : BlockSlot ,
2020-11-04 21:52:47 +00:00
committee_index : CommitteeIndex ) : AttestationData =
2020-08-10 13:21:31 +00:00
## Create an attestation / vote for the block `bs` using the
## data in `epochRef` to fill in the rest of the fields.
## `epochRef` is the epoch information corresponding to the `bs` advanced to
## the slot we're attesting to.
let
slot = bs . slot
2022-01-11 10:01:54 +00:00
current_epoch = slot . epoch ( )
epoch_boundary_slot = current_epoch . start_slot ( )
2020-08-10 13:21:31 +00:00
epoch_boundary_block = bs . blck . atSlot ( epoch_boundary_slot )
doAssert current_epoch = = epochRef . epoch
2024-03-14 06:26:36 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#attestation-data
2020-08-10 13:21:31 +00:00
AttestationData (
slot : slot ,
2022-01-08 23:28:49 +00:00
index : committee_index . asUInt64 ,
2020-08-10 13:21:31 +00:00
beacon_block_root : bs . blck . root ,
2022-07-06 10:33:02 +00:00
source : epochRef . checkpoints . justified ,
2020-08-10 13:21:31 +00:00
target : Checkpoint (
epoch : current_epoch ,
2022-07-06 10:33:02 +00:00
root : epoch_boundary_block . blck . root ) )
2021-03-30 15:01:47 +00:00
2024-03-14 06:26:36 +00:00
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#validator-assignments
2021-03-30 15:01:47 +00:00
iterator get_committee_assignments * (
2022-08-18 18:07:01 +00:00
shufflingRef : ShufflingRef , validator_indices : HashSet [ ValidatorIndex ] ) :
2022-01-08 23:28:49 +00:00
tuple [ committee_index : CommitteeIndex ,
2021-05-10 07:13:36 +00:00
subnet_id : SubnetId , slot : Slot ] =
2021-03-30 15:01:47 +00:00
let
2022-08-18 18:07:01 +00:00
committees_per_slot = get_committee_count_per_slot ( shufflingRef )
epoch = shufflingRef . epoch
2021-03-30 15:01:47 +00:00
2022-01-11 10:01:54 +00:00
for slot in epoch . slots ( ) :
2022-01-08 23:28:49 +00:00
for committee_index in get_committee_indices ( committees_per_slot ) :
2022-08-18 18:07:01 +00:00
if anyIt ( get_beacon_committee ( shufflingRef , slot , committee_index ) , it in validator_indices ) :
2021-03-30 15:01:47 +00:00
yield (
2022-01-08 23:28:49 +00:00
committee_index ,
compute_subnet_for_attestation ( committees_per_slot , slot , committee_index ) ,
2021-03-30 15:01:47 +00:00
slot )
2021-08-24 19:49:51 +00:00
2022-08-18 18:07:01 +00:00
func is_aggregator * ( shufflingRef : ShufflingRef , slot : Slot ,
index : CommitteeIndex , slot_signature : ValidatorSig ) : bool =
2021-08-24 19:49:51 +00:00
let
2022-08-18 18:07:01 +00:00
committee_len = get_beacon_committee_len ( shufflingRef , slot , index )
2021-08-24 19:49:51 +00:00
return is_aggregator ( committee_len , slot_signature )