remove some BeaconState use and abstract over other uses (#2482)

* remove some BeaconState use and abstract over other uses

* remove out-of-context comment
This commit is contained in:
tersec 2021-04-08 08:24:25 +00:00 committed by GitHub
parent 5f5e3e43c3
commit d3cad92693
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 98 additions and 82 deletions

View File

@ -47,12 +47,6 @@ proc init*(T: type BeaconClock, genesis_time: uint64): T =
T(genesis: unixGenesis - unixGenesisOffset)
proc init*(T: type BeaconClock, state: BeaconState): T =
## Initialize time from a beacon state. The genesis time of a beacon state is
## constant throughout its lifetime, so the state from any slot will do,
## including the genesis state.
BeaconClock.init(state.genesis_time)
template `<`*(a, b: BeaconTime): bool =
Duration(a) < Duration(b)

View File

@ -78,8 +78,10 @@ proc init*(T: type AttestationPool, chainDag: ChainDAGRef, quarantine: Quarantin
doAssert status.isOk(), "Error in preloading the fork choice: " & $status.error
info "Fork choice initialized",
justified_epoch = chainDag.headState.data.data.current_justified_checkpoint.epoch,
finalized_epoch = chainDag.headState.data.data.finalized_checkpoint.epoch,
justified_epoch = getStateField(
chainDag.headState, current_justified_checkpoint).epoch,
finalized_epoch = getStateField(
chainDag.headState, finalized_checkpoint).epoch,
finalized_root = shortlog(chainDag.finalizedHead.blck.root)
T(

View File

@ -79,7 +79,7 @@ proc addResolvedBlock(
onBlockAdded: OnBlockAdded
) =
# TODO move quarantine processing out of here
doAssert state.data.data.slot == trustedBlock.message.slot,
doAssert getStateField(state, slot) == trustedBlock.message.slot,
"state must match block"
doAssert state.blck.root == trustedBlock.message.parent_root,
"the StateData passed into the addResolved function not yet updated!"

View File

@ -301,6 +301,9 @@ proc loadStateCache*(
if epoch > 0:
load(epoch - 1)
template getStateField*(stateData, fieldName: untyped): untyped =
stateData.data.data.fieldName
func init(T: type BlockRef, root: Eth2Digest, slot: Slot): BlockRef =
BlockRef(
root: root,
@ -433,7 +436,7 @@ proc init*(T: type ChainDAGRef,
# When we start from a snapshot state, the `finalized_checkpoint` in the
# snapshot will point to an even older state, but we trust the tail state
# (the snapshot) to be finalized, hence the `max` expression below.
let finalizedEpoch = max(res.headState.data.data.finalized_checkpoint.epoch,
let finalizedEpoch = max(getStateField(res.headState, finalized_checkpoint).epoch,
tailRef.slot.epoch)
res.finalizedHead = headRef.atEpochStart(finalizedEpoch)
@ -566,10 +569,10 @@ proc putState*(dag: ChainDAGRef, state: var StateData) =
# Store a state and its root
logScope:
blck = shortLog(state.blck)
stateSlot = shortLog(state.data.data.slot)
stateSlot = shortLog(getStateField(state, slot))
stateRoot = shortLog(state.data.root)
if not isStateCheckpoint(state.blck.atSlot(state.data.data.slot)):
if not isStateCheckpoint(state.blck.atSlot(getStateField(state, slot))):
return
if dag.db.containsState(state.data.root):
@ -582,10 +585,11 @@ proc putState*(dag: ChainDAGRef, state: var StateData) =
dag.db.putState(state.data.root, state.data.data)
# Allow backwards-compatible version rollback with bounded recovery cost
if state.data.data.slot.epoch mod 64 == 0:
if getStateField(state, slot).epoch mod 64 == 0:
dag.db.putStateFull(state.data.root, state.data.data)
dag.db.putStateRoot(state.blck.root, state.data.data.slot, state.data.root)
dag.db.putStateRoot(
state.blck.root, getStateField(state, slot), state.data.root)
func getRef*(dag: ChainDAGRef, root: Eth2Digest): BlockRef =
## Retrieve a resolved block reference, if available
@ -687,10 +691,10 @@ proc advanceSlots(
# Given a state, advance it zero or more slots by applying empty slot
# processing - the state must be positions at a slot before or equal to the
# target
doAssert state.data.data.slot <= slot
while state.data.data.slot < slot:
doAssert getStateField(state, slot) <= slot
while getStateField(state, slot) < slot:
doAssert process_slots(
state.data, state.data.data.slot + 1, cache,
state.data, getStateField(state, slot) + 1, cache,
dag.updateFlags),
"process_slots shouldn't fail when state slot is correct"
if save:
@ -744,7 +748,7 @@ proc updateStateData*(
template canAdvance(state: StateData, bs: BlockSlot): bool =
# The block is the same and we're at an early enough slot - the state can
# be used to arrive at the desired blockslot
state.blck == bs.blck and state.data.data.slot <= bs.slot
state.blck == bs.blck and getStateField(state, slot) <= bs.slot
# First, run a quick check if we can simply apply a few blocks to an in-memory
# state - any in-memory state will be faster than loading from database.
@ -790,7 +794,7 @@ proc updateStateData*(
if not found:
debug "UpdateStateData cache miss",
bs, stateBlock = state.blck, stateSlot = state.data.data.slot
bs, stateBlock = state.blck, stateSlot = getStateField(state, slot)
# Either the state is too new or was created by applying a different block.
# We'll now resort to loading the state from the database then reapplying
@ -823,7 +827,7 @@ proc updateStateData*(
beacon_state_rewinds.inc()
let
startSlot {.used.} = state.data.data.slot # used in logs below
startSlot {.used.} = getStateField(state, slot) # used in logs below
startRoot {.used.} = state.data.root
# Time to replay all the blocks between then and now
for i in countdown(ancestors.len - 1, 0):
@ -844,9 +848,9 @@ proc updateStateData*(
logScope:
blocks = ancestors.len
slots = state.data.data.slot - startSlot
slots = getStateField(state, slot) - startSlot
stateRoot = shortLog(state.data.root)
stateSlot = state.data.data.slot
stateSlot = getStateField(state, slot)
startRoot = shortLog(startRoot)
startSlot
blck = shortLog(bs)
@ -999,7 +1003,7 @@ proc updateHead*(
let
finalizedHead = newHead.atEpochStart(
dag.headState.data.data.finalized_checkpoint.epoch)
getStateField(dag.headState, finalized_checkpoint).epoch)
doAssert (not finalizedHead.blck.isNil),
"Block graph should always lead to a finalized block"
@ -1010,9 +1014,10 @@ proc updateHead*(
headParent = shortLog(newHead.parent),
stateRoot = shortLog(dag.headState.data.root),
headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(dag.headState.data.data.slot),
justified = shortLog(dag.headState.data.data.current_justified_checkpoint),
finalized = shortLog(dag.headState.data.data.finalized_checkpoint)
stateSlot = shortLog(getStateField(dag.headState, slot)),
justified =
shortLog(getStateField(dag.headState, current_justified_checkpoint)),
finalized = shortLog(getStateField(dag.headState, finalized_checkpoint))
# A reasonable criterion for "reorganizations of the chain"
quarantine.clearQuarantine()
@ -1021,17 +1026,19 @@ proc updateHead*(
debug "Updated head block",
stateRoot = shortLog(dag.headState.data.root),
headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(dag.headState.data.data.slot),
justified = shortLog(dag.headState.data.data.current_justified_checkpoint),
finalized = shortLog(dag.headState.data.data.finalized_checkpoint)
stateSlot = shortLog(getStateField(dag.headState, slot)),
justified = shortLog(getStateField(
dag.headState, current_justified_checkpoint)),
finalized = shortLog(getStateField(
dag.headState, finalized_checkpoint))
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics
# both non-negative, so difference can't overflow or underflow int64
beacon_pending_deposits.set(
dag.headState.data.data.eth1_data.deposit_count.toGaugeValue -
dag.headState.data.data.eth1_deposit_index.toGaugeValue)
getStateField(dag.headState, eth1_data).deposit_count.toGaugeValue -
getStateField(dag.headState, eth1_deposit_index).toGaugeValue)
beacon_processed_deposits_total.set(
dag.headState.data.data.eth1_deposit_index.toGaugeValue)
getStateField(dag.headState, eth1_deposit_index).toGaugeValue)
beacon_head_root.set newHead.root.toGaugeValue
beacon_head_slot.set newHead.slot.toGaugeValue
@ -1041,13 +1048,17 @@ proc updateHead*(
# changes epoch, even if there is no new block / head, but we'll delay
# updating them until a block confirms the change
beacon_current_justified_epoch.set(
dag.headState.data.data.current_justified_checkpoint.epoch.toGaugeValue)
getStateField(
dag.headState, current_justified_checkpoint).epoch.toGaugeValue)
beacon_current_justified_root.set(
dag.headState.data.data.current_justified_checkpoint.root.toGaugeValue)
getStateField(
dag.headState, current_justified_checkpoint).root.toGaugeValue)
beacon_previous_justified_epoch.set(
dag.headState.data.data.previous_justified_checkpoint.epoch.toGaugeValue)
getStateField(
dag.headState, previous_justified_checkpoint).epoch.toGaugeValue)
beacon_previous_justified_root.set(
dag.headState.data.data.previous_justified_checkpoint.root.toGaugeValue)
getStateField(
dag.headState, previous_justified_checkpoint).root.toGaugeValue)
let epochRef = getEpochRef(dag, newHead, newHead.slot.epoch)
beacon_active_validators.set(
@ -1061,9 +1072,9 @@ proc updateHead*(
dag.finalizedHead = finalizedHead
beacon_finalized_epoch.set(
dag.headState.data.data.finalized_checkpoint.epoch.toGaugeValue)
getStateField(dag.headState, finalized_checkpoint).epoch.toGaugeValue)
beacon_finalized_root.set(
dag.headState.data.data.finalized_checkpoint.root.toGaugeValue)
getStateField(dag.headState, finalized_checkpoint).root.toGaugeValue)
# Pruning the block dag is required every time the finalized head changes
# in order to clear out blocks that are no longer viable and should

View File

@ -111,7 +111,7 @@ func getExitMessagesForBlock[T](
if allIt(
getValidatorIndices(exit_message),
pool.chainDag.headState.data.data.validators[it].exit_epoch !=
getStateField(pool.chainDag.headState, validators)[it].exit_epoch !=
FAR_FUTURE_EPOCH):
# A beacon block exit message already targeted all these validators
continue

View File

@ -251,9 +251,9 @@ proc validateAttestation*(
"validateAttestation: number of aggregation bits and committee size mismatch")))
let
fork = pool.chainDag.headState.data.data.fork
fork = getStateField(pool.chainDag.headState, fork)
genesis_validators_root =
pool.chainDag.headState.data.data.genesis_validators_root
getStateField(pool.chainDag.headState, genesis_validators_root)
attesting_indices = get_attesting_indices(
epochRef, attestation.data, attestation.aggregation_bits)
@ -420,9 +420,9 @@ proc validateAggregate*(
return err((ValidationResult.Reject, cstring("Invalid aggregator_index")))
let
fork = pool.chainDag.headState.data.data.fork
fork = getStateField(pool.chainDag.headState, fork)
genesis_validators_root =
pool.chainDag.headState.data.data.genesis_validators_root
getStateField(pool.chainDag.headState, genesis_validators_root)
let deferredCrypto = batchCrypto
.scheduleAggregateChecks(
@ -567,7 +567,7 @@ proc isValidBeaconBlock*(
# compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) ==
# store.finalized_checkpoint.root
let
finalized_checkpoint = dag.headState.data.data.finalized_checkpoint
finalized_checkpoint = getStateField(dag.headState, finalized_checkpoint)
ancestor = get_ancestor(
parent_ref, compute_start_slot_at_epoch(finalized_checkpoint.epoch))
@ -601,8 +601,8 @@ proc isValidBeaconBlock*(
# [REJECT] The proposer signature, signed_beacon_block.signature, is valid
# with respect to the proposer_index pubkey.
if not verify_block_signature(
dag.headState.data.data.fork,
dag.headState.data.data.genesis_validators_root,
getStateField(dag.headState, fork),
getStateField(dag.headState, genesis_validators_root),
signed_beacon_block.message.slot,
signed_beacon_block.message,
proposer.get()[1],
@ -690,11 +690,11 @@ proc validateVoluntaryExit*(
# [IGNORE] The voluntary exit is the first valid voluntary exit received for
# the validator with index signed_voluntary_exit.message.validator_index.
if signed_voluntary_exit.message.validator_index >=
pool.chainDag.headState.data.data.validators.lenu64:
getStateField(pool.chainDag.headState, validators).lenu64:
return err((ValidationResult.Ignore, cstring(
"validateVoluntaryExit: validator index too high")))
# Since pool.chainDag.headState.data.data.validators is a seq, this means
# Given that getStateField(pool.chainDag.headState, validators) is a seq,
# signed_voluntary_exit.message.validator_index.int is already valid, but
# check explicitly if one changes that data structure.
if signed_voluntary_exit.message.validator_index.int in

View File

@ -78,10 +78,10 @@ declareGauge next_action_wait,
logScope: topics = "beacnde"
func enrForkIdFromState(state: BeaconState): ENRForkID =
func getEnrForkId(fork: Fork, genesis_validators_root: Eth2Digest): ENRForkID =
let
forkVer = state.fork.current_version
forkDigest = compute_fork_digest(forkVer, state.genesis_validators_root)
forkVer = fork.current_version
forkDigest = compute_fork_digest(forkVer, genesis_validators_root)
ENRForkID(
fork_digest: forkDigest,
@ -232,10 +232,11 @@ proc init*(T: type BeaconNode,
chainDagFlags = if config.verifyFinalization: {verifyFinalization}
else: {}
chainDag = ChainDAGRef.init(runtimePreset, db, chainDagFlags)
beaconClock = BeaconClock.init(chainDag.headState.data.data)
beaconClock =
BeaconClock.init(getStateField(chainDag.headState, genesis_time))
quarantine = QuarantineRef.init(rng)
databaseGenesisValidatorsRoot =
chainDag.headState.data.data.genesis_validators_root
getStateField(chainDag.headState, genesis_validators_root)
if genesisStateContents.len != 0:
let
@ -260,7 +261,7 @@ proc init*(T: type BeaconNode,
error "Weak subjectivity checkpoint is stale",
currentSlot,
checkpoint = config.weakSubjectivityCheckpoint.get,
headStateSlot = chainDag.headState.data.data.slot
headStateSlot = getStateField(chainDag.headState, slot)
quit 1
if checkpointState != nil:
@ -295,7 +296,9 @@ proc init*(T: type BeaconNode,
netKeys = getPersistentNetKeys(rng[], config)
nickname = if config.nodeName == "auto": shortForm(netKeys)
else: config.nodeName
enrForkId = enrForkIdFromState(chainDag.headState.data.data)
enrForkId = getEnrForkId(
getStateField(chainDag.headState, fork),
getStateField(chainDag.headState, genesis_validators_root))
topicBeaconBlocks = getBeaconBlocksTopic(enrForkId.forkDigest)
topicAggregateAndProofs = getAggregateAndProofsTopic(enrForkId.forkDigest)
network = createEth2Node(rng, config, netKeys, enrForkId)
@ -308,7 +311,7 @@ proc init*(T: type BeaconNode,
info "Loading slashing protection database",
path = config.validatorsDir()
SlashingProtectionDB.init(
chainDag.headState.data.data.genesis_validators_root,
getStateField(chainDag.headState, genesis_validators_root),
config.validatorsDir(), "slashing_protection",
modes = {kCompleteArchiveV1},
disagreementBehavior = kChooseV1
@ -317,14 +320,14 @@ proc init*(T: type BeaconNode,
info "Loading slashing protection database (v2)",
path = config.validatorsDir()
SlashingProtectionDB.init(
chainDag.headState.data.data.genesis_validators_root,
getStateField(chainDag.headState, genesis_validators_root),
config.validatorsDir(), "slashing_protection"
)
of SlashingDbKind.both:
info "Loading slashing protection database (dual DB mode)",
path = config.validatorsDir()
SlashingProtectionDB.init(
chainDag.headState.data.data.genesis_validators_root,
getStateField(chainDag.headState, genesis_validators_root),
config.validatorsDir(), "slashing_protection",
modes = {kCompleteArchiveV1, kCompleteArchiveV2},
disagreementBehavior = kChooseV2
@ -455,7 +458,8 @@ func getStabilitySubnets(stabilitySubnets: auto): set[uint8] =
proc getAttachedValidators(node: BeaconNode):
Table[ValidatorIndex, AttachedValidator] =
for validatorIndex in 0 ..< node.chainDag.headState.data.data.validators.len:
for validatorIndex in 0 ..<
getStateField(node.chainDag.headState, validators).len:
let attachedValidator = node.getAttachedValidator(
node.chainDag.headState.data.data, validatorIndex.ValidatorIndex)
if attachedValidator.isNil:
@ -489,8 +493,9 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
is_aggregator(
committeeLen,
await attachedValidators[it.ValidatorIndex].getSlotSig(
node.chainDag.headState.data.data.fork,
node.chainDag.headState.data.data.genesis_validators_root, slot)))
getStateField(node.chainDag.headState, fork),
getStateField(
node.chainDag.headState, genesis_validators_root), slot)))
node.attestationSubnets.lastCalculatedEpoch = epoch
node.attestationSubnets.attestingSlots[epoch mod 2] = 0
@ -571,10 +576,10 @@ proc cycleAttestationSubnetsPerEpoch(
# wallSlot, it would have to look more than MIN_SEED_LOOKAHEAD epochs
# ahead to compute the shuffling determining the beacon committees.
static: doAssert MIN_SEED_LOOKAHEAD == 1
if node.chainDag.headState.data.data.slot.epoch != wallSlot.epoch:
if getStateField(node.chainDag.headState, slot).epoch != wallSlot.epoch:
debug "Requested attestation subnets too far in advance",
wallSlot,
stateSlot = node.chainDag.headState.data.data.slot
stateSlot = getStateField(node.chainDag.headState, slot)
return prevStabilitySubnets
# This works so long as at least one block in an epoch provides a basis for
@ -1351,7 +1356,7 @@ proc initStatusBar(node: BeaconNode) {.raises: [Defect, ValueError].} =
proc dataResolver(expr: string): string {.raises: [Defect].} =
template justified: untyped = node.chainDag.head.atEpochStart(
node.chainDag.headState.data.data.current_justified_checkpoint.epoch)
getStateField(node.chainDag.headState, current_justified_checkpoint).epoch)
# TODO:
# We should introduce a general API for resolving dot expressions
# such as `db.latest_block.slot` or `metrics.connected_peers`.
@ -1739,7 +1744,8 @@ proc doCreateTestnet(config: BeaconNodeConf, rng: var BrHmacDrbgContext) {.raise
some(config.bootstrapAddress),
some(config.bootstrapPort),
some(config.bootstrapPort),
[toFieldPair("eth2", SSZ.encode(enrForkIdFromState initialState[])),
[toFieldPair("eth2", SSZ.encode(getEnrForkId(
initialState[].fork, initialState[].genesis_validators_root))),
toFieldPair("attnets", SSZ.encode(netMetadata.attnets))])
writeFile(bootstrapFile, bootstrapEnr.tryGet().toURI)

View File

@ -182,9 +182,9 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_beacon_genesis") do () -> BeaconGenesisTuple:
return (
genesis_time: node.chainDag.headState.data.data.genesis_time,
genesis_time: getStateField(node.chainDag.headState, genesis_time),
genesis_validators_root:
node.chainDag.headState.data.data.genesis_validators_root,
getStateField(node.chainDag.headState, genesis_validators_root),
genesis_fork_version: node.runtimePreset.GENESIS_FORK_VERSION
)

View File

@ -33,7 +33,7 @@ func getDepositAddress(node: BeaconNode): string =
proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_config_fork_schedule") do () -> seq[Fork]:
return @[node.chainDag.headState.data.data.fork]
return @[getStateField(node.chainDag.headState, fork)]
rpcServer.rpc("get_v1_config_spec") do () -> JsonNode:
return %*{

View File

@ -43,8 +43,9 @@ proc installNimbusApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("getChainHead") do () -> JsonNode:
let
head = node.chainDag.head
finalized = node.chainDag.headState.data.data.finalized_checkpoint
justified = node.chainDag.headState.data.data.current_justified_checkpoint
finalized = getStateField(node.chainDag.headState, finalized_checkpoint)
justified =
getStateField(node.chainDag.headState, current_justified_checkpoint)
return %* {
"head_slot": head.slot,
"head_block_root": head.root.data.toHex(),

View File

@ -21,7 +21,7 @@ template withStateForStateId*(stateId: string, body: untyped): untyped =
bs = node.stateIdToBlockSlot(stateId)
template isState(state: StateData): bool =
state.blck.atSlot(state.data.data.slot) == bs
state.blck.atSlot(getStateField(state, slot)) == bs
if isState(node.chainDag.headState):
withStateVars(node.chainDag.headState):
@ -75,7 +75,7 @@ proc stateIdToBlockSlot*(node: BeaconNode, stateId: string): BlockSlot {.raises:
node.chainDag.finalizedHead
of "justified":
node.chainDag.head.atEpochStart(
node.chainDag.headState.data.data.current_justified_checkpoint.epoch)
getStateField(node.chainDag.headState, current_justified_checkpoint).epoch)
else:
if stateId.startsWith("0x"):
let blckRoot = parseRoot(stateId)

View File

@ -141,8 +141,8 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
"Slot requested not in current or next wall-slot epoch")
if not verify_slot_signature(
node.chainDag.headState.data.data.fork,
node.chainDag.headState.data.data.genesis_validators_root,
getStateField(node.chainDag.headState, fork),
getStateField(node.chainDag.headState, genesis_validators_root),
slot, validator_pubkey, slot_signature):
raise newException(CatchableError,
"Invalid slot signature")

View File

@ -84,8 +84,10 @@ proc getCurrentStatus*(state: BeaconSyncNetworkState): StatusMsg {.gcsafe.} =
StatusMsg(
forkDigest: state.forkDigest,
finalizedRoot: chainDag.headState.data.data.finalized_checkpoint.root,
finalizedEpoch: chainDag.headState.data.data.finalized_checkpoint.epoch,
finalizedRoot:
getStateField(chainDag.headState, finalized_checkpoint).root,
finalizedEpoch:
getStateField(chainDag.headState, finalized_checkpoint).epoch,
headRoot: headBlock.root,
headSlot: headBlock.slot)

View File

@ -345,9 +345,9 @@ proc proposeBlock(node: BeaconNode,
return head
let
fork = node.chainDag.headState.data.data.fork
fork = getStateField(node.chainDag.headState, fork)
genesis_validators_root =
node.chainDag.headState.data.data.genesis_validators_root
getStateField(node.chainDag.headState, genesis_validators_root)
let
randao = await validator.genRandaoReveal(
fork, genesis_validators_root, slot)
@ -417,9 +417,9 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
committees_per_slot =
get_committee_count_per_slot(epochRef)
num_active_validators = count_active_validators(epochRef)
fork = node.chainDag.headState.data.data.fork
fork = getStateField(node.chainDag.headState, fork)
genesis_validators_root =
node.chainDag.headState.data.data.genesis_validators_root
getStateField(node.chainDag.headState, genesis_validators_root)
for committee_index in 0'u64..<committees_per_slot:
let committee = get_beacon_committee(
@ -498,9 +498,9 @@ proc broadcastAggregatedAttestations(
let
epochRef = node.chainDag.getEpochRef(aggregationHead, aggregationSlot.epoch)
fork = node.chainDag.headState.data.data.fork
fork = getStateField(node.chainDag.headState, fork)
genesis_validators_root =
node.chainDag.headState.data.data.genesis_validators_root
getStateField(node.chainDag.headState, genesis_validators_root)
committees_per_slot = get_committee_count_per_slot(epochRef)
var