incorporate proposals into nextActionWait; switch some proc to func (#2438)

This commit is contained in:
tersec 2021-03-24 10:05:04 +00:00 committed by GitHub
parent a727fc8e52
commit 36311bfc05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 56 deletions

View File

@ -161,9 +161,10 @@ type
subscribeSlot*: array[ATTESTATION_SUBNET_COUNT, Slot]
unsubscribeSlot*: array[ATTESTATION_SUBNET_COUNT, Slot]
# Used to track the next attestation slots, using an epoch-relative
# coordinate system. Defaults don't need initialization.
# Used to track the next attestation and proposal slots using an
# epoch-relative coordinate system. Doesn't need initialization.
attestingSlots*: array[2, uint32]
lastCalculatedAttestationEpoch*: Epoch
proposingSlots*: array[2, uint32]
lastCalculatedEpoch*: Epoch
func shortLog*(v: AttachedValidator): string = shortLog(v.pubKey)

View File

@ -37,8 +37,10 @@ import
validator_api],
./spec/[
datatypes, digest, crypto, beaconstate, eth2_apis/beacon_rpc_client,
helpers, network, presets, validator, weak_subjectivity, signatures],
./consensus_object_pools/[blockchain_dag, block_quarantine, block_clearance, block_pools_types, attestation_pool, exit_pool],
helpers, network, presets, weak_subjectivity, signatures],
./consensus_object_pools/[
blockchain_dag, block_quarantine, block_clearance, block_pools_types,
attestation_pool, exit_pool, spec_cache],
./eth1/eth1_monitor
from eth/common/eth_types import BlockHashOrNumber
@ -456,32 +458,17 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#lookahead
# Only subscribe when this node should aggregate; libp2p broadcasting works
# on subnet topics regardless.
#
# Committee sizes in any given epoch vary by 1, i.e. committee sizes $n$
# $n+1$ can exist. Furthermore, according to
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#aggregation-selection
# is_aggregator uses `len(committee) div TARGET_AGGREGATORS_PER_COMMITTEE`
# to determine whether committee length/slot signature pairs aggregate the
# attestations in a slot/committee, where TARGET_AGGREGATORS_PER_COMMITTEE
# is currently 16 in all defined presets. Therefore, probe a committee len
# to determine whether it's possible that it's within a boundary such that
# either that length or other possible committee lengths don't cross those
# div/mod 16 boundaries which would change is_aggregator results.
static: doAssert TARGET_AGGREGATORS_PER_COMMITTEE == 16 # mainnet, minimal
let epochRef = node.chainDag.getEpochRef(node.chainDag.head, epoch)
let
probeCommitteeLen = get_beacon_committee_len(
node.chainDag.headState.data.data, compute_start_slot_at_epoch(epoch),
0.CommitteeIndex, cache)
# Without knowing whether probeCommitteeLen is the higher or lower, if it's
# [-1, 1] mod TARGET_AGGREGATORS_PER_COMMITTEE it might cross boundaries in
# is_aggregator, such that one can't hoist committee length calculation out
# of the anyIt(...) loop.
isConstAggregationLen =
(probeCommitteeLen mod TARGET_AGGREGATORS_PER_COMMITTEE) notin
[0'u64, 1'u64, TARGET_AGGREGATORS_PER_COMMITTEE - 1]
# Update proposals
node.attestationSubnets.proposingSlots[epoch mod 2] = 0
for i in 0 ..< SLOTS_PER_EPOCH:
let beaconProposer = epochRef.beacon_proposers[i]
if beaconProposer.isSome and beaconProposer.get()[0] in attachedValidators:
node.attestationsubnets.proposingSlots[epoch mod 2] =
node.attestationsubnets.proposingSlots[epoch mod 2] or (1'u32 shl i)
# Update attestations
template isAnyCommitteeValidatorAggregating(
validatorIndices, committeeLen: untyped, slot: Slot): bool =
anyIt(
@ -492,22 +479,17 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
node.chainDag.headState.data.data.fork,
node.chainDag.headState.data.data.genesis_validators_root, slot)))
# The relevant bitmap are 32 bits each.
static: doAssert SLOTS_PER_EPOCH <= 32
node.attestationSubnets.lastCalculatedAttestationEpoch = epoch
node.attestationSubnets.lastCalculatedEpoch = epoch
node.attestationSubnets.attestingSlots[epoch mod 2] = 0
# The relevant bitmaps are 32 bits each.
static: doAssert SLOTS_PER_EPOCH <= 32
for (validatorIndices, committeeIndex, subnetIndex, slot) in
get_committee_assignments(
node.chainDag.headState.data.data, epoch, validatorIndices, cache):
doAssert compute_epoch_at_slot(slot) == epoch
let committeeLen =
if isConstAggregationLen:
probeCommitteeLen
else:
get_beacon_committee_len(
node.chainDag.headState.data.data, slot, committeeIndex, cache)
# Each get_committee_assignments() call here is on the next epoch. At any
# given time, only care about two epochs, the current and next epoch. So,
@ -527,7 +509,8 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
(1'u32 shl (slot mod SLOTS_PER_EPOCH))
if not isAnyCommitteeValidatorAggregating(
validatorIndices, committeeLen, slot):
validatorIndices,
get_beacon_committee_len(epochRef, slot, committeeIndex), slot):
continue
node.attestationSubnets.unsubscribeSlot[subnetIndex] =
@ -544,11 +527,11 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
node.attestationSubnets.subscribeSlot[subnetIndex])
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#phase-0-attestation-subnet-stability
proc getStabilitySubnetLength(node: BeaconNode): uint64 =
func getStabilitySubnetLength(node: BeaconNode): uint64 =
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION +
node.network.rng[].rand(EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION.int).uint64
proc updateStabilitySubnets(node: BeaconNode, slot: Slot): set[uint8] =
func updateStabilitySubnets(node: BeaconNode, slot: Slot): set[uint8] =
# Equivalent to wallSlot by cycleAttestationSubnets(), especially
# since it'll try to run early in epochs, avoiding race conditions.
static: doAssert ATTESTATION_SUBNET_COUNT <= high(uint8)
@ -881,13 +864,14 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) =
# This exits early all but one call each epoch.
traceAsyncErrors node.cycleAttestationSubnets(slot)
func getNextAttestation(node: BeaconNode, slot: Slot): Slot =
# The relevant attestations are in, depending on calculated bounds:
func getNextValidatorAction(
actionSlotSource: auto, lastCalculatedEpoch: Epoch, slot: Slot): Slot =
# The relevant actions are in, depending on calculated bounds:
# [aS[epoch mod 2], aS[1 - (epoch mod 2)]]
# current epoch next epoch
let orderedAttestingSlots = [
node.attestationSubnets.attestingSlots[ slot.epoch mod 2'u64],
node.attestationSubnets.attestingSlots[1 - (slot.epoch mod 2'u64)]]
let orderedActionSlots = [
actionSlotSource[ slot.epoch mod 2'u64],
actionSlotSource[1 - (slot.epoch mod 2'u64)]]
static: doAssert MIN_ATTESTATION_INCLUSION_DELAY == 1
@ -897,15 +881,15 @@ func getNextAttestation(node: BeaconNode, slot: Slot): Slot =
for i in [0'u64, 1'u64]:
let bitmapEpoch = slot.epoch + i
if bitmapEpoch > node.attestationSubnets.lastCalculatedAttestationEpoch:
if bitmapEpoch > lastCalculatedEpoch:
return FAR_FUTURE_SLOT
for slotOffset in 0 ..< SLOTS_PER_EPOCH:
let nextAttestationSlot =
let nextActionSlot =
compute_start_slot_at_epoch(bitmapEpoch) + slotOffset
if ((orderedAttestingSlots[i] and (1'u32 shl slotOffset)) != 0) and
nextAttestationSlot > slot:
return nextAttestationSlot
if ((orderedActionSlots[i] and (1'u32 shl slotOffset)) != 0) and
nextActionSlot > slot:
return nextActionSlot
FAR_FUTURE_SLOT
@ -931,10 +915,23 @@ proc onSlotEnd(node: BeaconNode, slot: Slot) {.async.} =
# the database are synced with the filesystem.
node.db.checkpoint()
# -1 is a more useful output than 18446744073709551615 as an indicator of
# no future attestation/proposal known.
template displayInt64(x: Slot): int64 =
if x == high(uint64).Slot:
-1'i64
else:
toGaugeValue(x)
let
nextAttestationSlot = node.getNextAttestation(slot)
nextActionWaitTime =
saturate(fromNow(node.beaconClock, nextAttestationSlot))
nextAttestationSlot = getNextValidatorAction(
node.attestationSubnets.attestingSlots,
node.attestationSubnets.lastCalculatedEpoch, slot)
nextProposalSlot = getNextValidatorAction(
node.attestationSubnets.proposingSlots,
node.attestationSubnets.lastCalculatedEpoch, slot)
nextActionWaitTime = saturate(fromNow(
node.beaconClock, min(nextAttestationSlot, nextProposalSlot)))
info "Slot end",
slot = shortLog(slot),
@ -944,7 +941,8 @@ proc onSlotEnd(node: BeaconNode, slot: Slot) {.async.} =
finalizedHead = shortLog(node.chainDag.finalizedHead.blck),
finalizedEpoch =
shortLog(node.chainDag.finalizedHead.blck.slot.compute_epoch_at_slot()),
nextAttestationSlot,
nextAttestationSlot = displayInt64(nextAttestationSlot),
nextProposalSlot = displayInt64(nextProposalSlot),
nextActionWait =
if nextAttestationSlot == FAR_FUTURE_SLOT:
"n/a"
@ -1138,7 +1136,7 @@ proc startSyncManager(node: BeaconNode) =
)
node.syncManager.start()
proc connectedPeersCount(node: BeaconNode): int =
func connectedPeersCount(node: BeaconNode): int =
len(node.network.peerPool)
proc installRpcHandlers(rpcServer: RpcServer, node: BeaconNode) =

View File

@ -124,6 +124,8 @@ proc process_deposit*(preset: RuntimePreset,
# New validator! Add validator and balance entries
state.validators.add(get_validator_from_deposit(deposit.data))
state.balances.add(amount)
doAssert state.validators.len == state.balances.len
else:
# Deposits may come with invalid signatures - in that case, they are not
# turned into a validator but still get processed to keep the deposit