VC: various fixes (#2730)

* Fix firstSuccess() template missing timeouts.

* Fix validator race condition.
Fix logs to be compatible with beacon_node logs.
Add CatchableError handlers to avoid crashes.
Move some logs from Notice to Debug level.
Fix some [unused] warnings.

* Fix block proposal issue for slots in the past and from the future.

* Change sent to published.

* Address review comments #1.
This commit is contained in:
Eugene Kabanov 2021-07-19 17:31:02 +03:00 committed by GitHub
parent 3e3e17fec3
commit f0c30e31b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 264 additions and 147 deletions

View File

@ -186,7 +186,7 @@ programMain:
fatal "Not enough beacon nodes in command line" fatal "Not enough beacon nodes in command line"
quit 1 quit 1
debug "Launching validator client", version = fullVersionStr, notice "Launching validator client", version = fullVersionStr,
cmdParams = commandLineParams(), cmdParams = commandLineParams(),
config, config,
beacon_nodes_count = len(beaconNodes) beacon_nodes_count = len(beaconNodes)

View File

@ -342,27 +342,30 @@ template firstSuccessTimeout*(vc: ValidatorClientRef, respType: typedesc,
RestBeaconNodeStatus.Uninitalized} RestBeaconNodeStatus.Uninitalized}
let offlineNodes = vc.beaconNodes.filterIt(it.status in offlineMask) let offlineNodes = vc.beaconNodes.filterIt(it.status in offlineMask)
warn "There no beacon nodes available, refreshing nodes status", warn "No working beacon nodes available, refreshing nodes status",
online_nodes = len(onlineNodes), offline_nodes = len(offlineNodes) online_nodes = len(onlineNodes), offline_nodes = len(offlineNodes)
var checkFut = vc.checkNodes(offlineMask) var checkFut = vc.checkNodes(offlineMask)
let checkOp = let checkOp =
block: block:
var dontRushFut = sleepAsync(500.milliseconds)
if isNil(timerFut): if isNil(timerFut):
try: try:
# We use `allFutures()` to keep result in `checkFut`, but still # We use `allFutures()` to keep result in `checkFut`, but still
# be able to check errors. # be able to check errors.
await allFutures(checkFut, dontRushFut) await allFutures(checkFut)
let onlineCount = vc.beaconNodes.countIt(
it.status == RestBeaconNodeStatus.Online)
if onlineCount == 0:
# Small pause here to avoid continous spam beacon nodes with
# checking requests.
await sleepAsync(500.milliseconds)
ApiOperation.Success ApiOperation.Success
except CancelledError: except CancelledError:
# `allFutures()` could not cancel Futures. # `allFutures()` could not cancel Futures.
if not(checkFut.finished()): if not(checkFut.finished()):
checkFut.cancel() checkFut.cancel()
if not(dontRushFut.finished()): await allFutures(checkFut)
dontRushFut.cancel()
await allFutures(checkFut, dontRushFut)
ApiOperation.Interrupt ApiOperation.Interrupt
except CatchableError as exc: except CatchableError as exc:
# This only could happened if `race()` or `allFutures()` start raise # This only could happened if `race()` or `allFutures()` start raise
@ -370,24 +373,26 @@ template firstSuccessTimeout*(vc: ValidatorClientRef, respType: typedesc,
ApiOperation.Failure ApiOperation.Failure
else: else:
try: try:
discard await race(allFutures(checkFut, dontRushFut), timerFut) discard await race(checkFut, timerFut)
if checkFut.finished(): if checkFut.finished():
let onlineCount = vc.beaconNodes.countIt(
it.status == RestBeaconNodeStatus.Online)
if onlineCount == 0:
# Small pause here to avoid continous spam beacon nodes with
# checking requests.
await sleepAsync(500.milliseconds)
ApiOperation.Success ApiOperation.Success
else: else:
checkFut.cancel() checkFut.cancel()
if not(dontRushFut.finished()): await allFutures(checkFut)
dontRushFut.cancel()
await allFutures(checkFut, dontRushFut)
ApiOperation.Timeout ApiOperation.Timeout
except CancelledError: except CancelledError:
# `race()` and `allFutures()` could not cancel Futures. # `race()` and `allFutures()` could not cancel Futures.
if not(timerFut.finished()): if not(timerFut.finished()):
timerFut.cancel() timerFut.cancel()
if not(dontRushFut.finished()):
dontRushFut.cancel()
if not(checkFut.finished()): if not(checkFut.finished()):
checkFut.cancel() checkFut.cancel()
await allFutures(checkFut, dontRushFut, timerFut) await allFutures(checkFut, timerFut)
ApiOperation.Interrupt ApiOperation.Interrupt
except CatchableError as exc: except CatchableError as exc:
# This only could happened if `race` or `allFutures` start raise # This only could happened if `race` or `allFutures` start raise

View File

@ -13,10 +13,12 @@ type
proc serveAttestation(service: AttestationServiceRef, adata: AttestationData, proc serveAttestation(service: AttestationServiceRef, adata: AttestationData,
duty: DutyAndProof): Future[bool] {.async.} = duty: DutyAndProof): Future[bool] {.async.} =
let vc = service.client let vc = service.client
let validator = vc.attachedValidators.getValidator(duty.data.pubkey) let validator =
if validator.index.isNone(): block:
warn "Validator index is missing", validator = validator.pubKey let res = vc.getValidator(duty.data.pubkey)
if res.isNone():
return false return false
res.get()
let fork = vc.fork.get() let fork = vc.fork.get()
@ -32,10 +34,10 @@ proc serveAttestation(service: AttestationServiceRef, adata: AttestationData,
adata.source.epoch, adata.source.epoch,
adata.target.epoch, signingRoot) adata.target.epoch, signingRoot)
if notSlashable.isErr(): if notSlashable.isErr():
warn "Slashing protection activated for attestation", slot = duty.data.slot, warn "Slashing protection activated for attestation",
validator = validator.pubKey, slot = duty.data.slot,
validator_index = duty.data.validator_index, validator = shortLog(validator),
badVoteDetails = $notSlashable.error validator_index = vindex, badVoteDetails = $notSlashable.error
return false return false
let attestation = await validator.produceAndSignAttestation(adata, let attestation = await validator.produceAndSignAttestation(adata,
@ -46,24 +48,35 @@ proc serveAttestation(service: AttestationServiceRef, adata: AttestationData,
let res = let res =
try: try:
await vc.submitPoolAttestations(@[attestation]) await vc.submitPoolAttestations(@[attestation])
except ValidatorApiError as exc: except ValidatorApiError:
error "Unable to submit attestation", slot = duty.data.slot, error "Unable to publish attestation",
validator = validator.pubKey, attestation = shortLog(attestation),
validator_index = duty.data.validator_index validator = shortLog(validator),
raise exc validator_index = vindex
return false
except CatchableError as exc:
error "Unexpected error occured while publishing attestation",
attestation = shortLog(attestation),
validator = shortLog(validator),
validator_index = vindex,
err_name = exc.name, err_msg = exc.msg
return false
let delay = vc.getDelay(seconds(int64(SECONDS_PER_SLOT) div 3)) let delay = vc.getDelay(seconds(int64(SECONDS_PER_SLOT) div 3))
let indexInCommittee = duty.data.validator_committee_index
if res: if res:
notice "Attestation published", validator = validator.pubKey, notice "Attestation published", attestation = shortLog(attestation),
validator_index = duty.data.validator_index, slot = duty.data.slot, validator = shortLog(validator),
delay = delay validator_index = vindex,
return true delay = delay,
indexInCommittee = indexInCommittee
else: else:
warn "Attestation was not accepted by beacon node", warn "Attestation was not accepted by beacon node",
validator = validator.pubKey, attestation = shortLog(attestation),
validator_index = duty.data.validator_index, validator = shortLog(validator),
slot = duty.data.slot, delay = delay validator_index = vindex, delay = delay,
return false indexInCommittee = indexInCommittee
return res
proc serveAggregateAndProof*(service: AttestationServiceRef, proc serveAggregateAndProof*(service: AttestationServiceRef,
proof: AggregateAndProof, proof: AggregateAndProof,
@ -78,16 +91,40 @@ proc serveAggregateAndProof*(service: AttestationServiceRef,
genesisRoot) genesisRoot)
let signedProof = SignedAggregateAndProof(message: proof, let signedProof = SignedAggregateAndProof(message: proof,
signature: signature) signature: signature)
let aggregationSlot = proof.aggregate.data.slot
let vindex = validator.index.get()
let res =
try: try:
return await vc.publishAggregateAndProofs(@[signedProof]): await vc.publishAggregateAndProofs(@[signedProof])
except ValidatorApiError: except ValidatorApiError:
warn "Unable to publish aggregate and proofs" error "Unable to publish aggregated attestation",
attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
aggregationSlot = aggregationSlot,
validator_index = vindex
return false return false
except CatchableError as exc: except CatchableError as exc:
error "Unexpected error happened", err_name = exc.name, error "Unexpected error occured while publishing aggregated attestation",
err_msg = exc.msg attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
aggregationSlot = aggregationSlot,
validator_index = vindex,
err_name = exc.name, err_msg = exc.msg
return false return false
if res:
notice "Aggregated attestation published",
attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
aggregationSlot = aggregationSlot, validator_index = vindex
else:
warn "Aggregated attestation was not accepted by beacon node",
attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
aggregationSlot = aggregationSlot, validator_index = vindex
return res
proc produceAndPublishAttestations*(service: AttestationServiceRef, proc produceAndPublishAttestations*(service: AttestationServiceRef,
slot: Slot, committee_index: CommitteeIndex, slot: Slot, committee_index: CommitteeIndex,
duties: seq[DutyAndProof] duties: seq[DutyAndProof]
@ -108,7 +145,8 @@ proc produceAndPublishAttestations*(service: AttestationServiceRef,
if (duty.data.slot != ad.slot) or if (duty.data.slot != ad.slot) or
(uint64(duty.data.committee_index) != ad.index): (uint64(duty.data.committee_index) != ad.index):
error "Inconsistent validator duties during attestation signing", error "Inconsistent validator duties during attestation signing",
validator = duty.data.pubkey, duty_slot = duty.data.slot, validator = shortLog(duty.data.pubkey),
duty_slot = duty.data.slot,
duty_index = duty.data.committee_index, duty_index = duty.data.committee_index,
attestation_slot = ad.slot, attestation_index = ad.index attestation_slot = ad.slot, attestation_index = ad.index
continue continue
@ -182,7 +220,13 @@ proc produceAndPublishAggregates(service: AttestationServiceRef,
try: try:
await vc.getAggregatedAttestation(slot, attestationRoot) await vc.getAggregatedAttestation(slot, attestationRoot)
except ValidatorApiError: except ValidatorApiError:
error "Unable to retrieve aggregated attestation data" error "Unable to get aggregated attestation data", slot = slot,
attestation_root = shortLog(attestationRoot)
return
except CatchableError as exc:
error "Unexpected error occured while getting aggregated attestation",
slot = slot, attestation_root = shortLog(attestationRoot),
err_name = exc.name, err_msg = exc.msg
return return
let pendingAggregates = let pendingAggregates =
@ -219,13 +263,13 @@ proc produceAndPublishAggregates(service: AttestationServiceRef,
(succeed, errored, failed) (succeed, errored, failed)
let delay = vc.getDelay(seconds((int64(SECONDS_PER_SLOT) div 3) * 2)) let delay = vc.getDelay(seconds((int64(SECONDS_PER_SLOT) div 3) * 2))
debug "Aggregate attestation statistics", total = len(pendingAggregates), debug "Aggregated attestation statistics", total = len(pendingAggregates),
succeed = statistics[0], failed_to_deliver = statistics[1], succeed = statistics[0], failed_to_deliver = statistics[1],
not_accepted = statistics[2], delay = delay, slot = slot, not_accepted = statistics[2], delay = delay, slot = slot,
committee_index = committeeIndex committee_index = committeeIndex
else: else:
notice "No aggregate and proofs scheduled for slot", slot = slot, debug "No aggregate and proofs scheduled for slot", slot = slot,
committee_index = committeeIndex committee_index = committeeIndex
proc publishAttestationsAndAggregates(service: AttestationServiceRef, proc publishAttestationsAndAggregates(service: AttestationServiceRef,
@ -242,22 +286,26 @@ proc publishAttestationsAndAggregates(service: AttestationServiceRef,
# TODO (cheatfate): Here should be present timeout. # TODO (cheatfate): Here should be present timeout.
let startTime = Moment.now() let startTime = Moment.now()
await vc.waitForBlockPublished(slot) await vc.waitForBlockPublished(slot)
let finishTime = Moment.now() let dur = Moment.now() - startTime
debug "Block proposal awaited", slot = slot, debug "Block proposal awaited", slot = slot, duration = dur
duration = (finishTime - startTime)
block: block:
let delay = vc.getDelay(seconds(int64(SECONDS_PER_SLOT) div 3)) let delay = vc.getDelay(seconds(int64(SECONDS_PER_SLOT) div 3))
notice "Producing attestations", delay = delay, slot = slot, debug "Producing attestations", delay = delay, slot = slot,
committee_index = committee_index, committee_index = committee_index,
duties_count = len(duties) duties_count = len(duties)
let ad = let ad =
try: try:
await service.produceAndPublishAttestations(slot, committee_index, await service.produceAndPublishAttestations(slot, committee_index, duties)
duties)
except ValidatorApiError: except ValidatorApiError:
error "Unable to proceed attestations" error "Unable to proceed attestations", slot = slot,
committee_index = committee_index, duties_count = len(duties)
return
except CatchableError as exc:
error "Unexpected error while producing attestations", slot = slot,
committee_index = committee_index, duties_count = len(duties),
err_name = exc.name, err_msg = exc.msg
return return
if aggregateTime != ZeroDuration: if aggregateTime != ZeroDuration:
@ -265,7 +313,7 @@ proc publishAttestationsAndAggregates(service: AttestationServiceRef,
block: block:
let delay = vc.getDelay(seconds((int64(SECONDS_PER_SLOT) div 3) * 2)) let delay = vc.getDelay(seconds((int64(SECONDS_PER_SLOT) div 3) * 2))
notice "Producing aggregate and proofs", delay = delay debug "Producing aggregate and proofs", delay = delay
await service.produceAndPublishAggregates(ad, duties) await service.produceAndPublishAggregates(ad, duties)
proc spawnAttestationTasks(service: AttestationServiceRef, proc spawnAttestationTasks(service: AttestationServiceRef,

View File

@ -5,11 +5,6 @@ logScope: service = "block_service"
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot, proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
validator: AttachedValidator) {.async.} = validator: AttachedValidator) {.async.} =
logScope:
validator = validator.pubKey
slot = slot
wallSlot = currentSlot
let let
genesisRoot = vc.beaconGenesis.genesis_validators_root genesisRoot = vc.beaconGenesis.genesis_validators_root
graffiti = graffiti =
@ -19,21 +14,26 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
defaultGraffitiBytes() defaultGraffitiBytes()
fork = vc.fork.get() fork = vc.fork.get()
debug "Publishing block", validator = validator.pubKey, debug "Publishing block", validator = shortLog(validator),
delay = vc.getDelay(ZeroDuration), delay = vc.getDelay(ZeroDuration),
wall_slot = currentSlot,
genesis_root = genesisRoot, genesis_root = genesisRoot,
graffiti = graffiti, fork = fork, slot = slot, graffiti = graffiti, fork = fork, slot = slot,
wall_slot = currentSlot wall_slot = currentSlot
try: try:
let randaoReveal = await validator.genRandaoReveal(fork, genesisRoot, slot) let randaoReveal = await validator.genRandaoReveal(fork, genesisRoot, slot)
let beaconBlock = let beaconBlock =
try: try:
await vc.produceBlock(slot, randaoReveal, graffiti) await vc.produceBlock(slot, randaoReveal, graffiti)
except ValidatorApiError as exc: except ValidatorApiError:
error "Unable to retrieve block data", slot = currentSlot, error "Unable to retrieve block data", slot = slot,
validator = validator.pubKey wall_slot = currentSlot, validator = shortLog(validator)
return return
except CatchableError as exc:
error "An unexpected error occurred while getting block data",
err_name = exc.name, err_msg = exc.msg
return
let blockRoot = hash_tree_root(beaconBlock) let blockRoot = hash_tree_root(beaconBlock)
var signedBlock = SignedBeaconBlock(message: beaconBlock, var signedBlock = SignedBeaconBlock(message: beaconBlock,
root: hash_tree_root(beaconBlock)) root: hash_tree_root(beaconBlock))
@ -55,28 +55,33 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
try: try:
await vc.publishBlock(signedBlock) await vc.publishBlock(signedBlock)
except ValidatorApiError: except ValidatorApiError:
error "Unable to submit block", slot = currentSlot, error "Unable to publish block", blck = shortLog(signedBlock.message),
validator = validator.pubKey, block_root = blockRoot, blockRoot = shortLog(blockRoot),
deposits = len(signedBlock.message.body.deposits), validator = shortLog(validator),
attestations = len(signedBlock.message.body.attestations), validator_index = validator.index.get(),
graffiti = graffiti wall_slot = currentSlot
return
except CatchableError as exc:
error "An unexpected error occurred while publishing block",
err_name = exc.name, err_msg = exc.msg
return return
if res: if res:
notice "Block published", slot = currentSlot, notice "Block published", blck = shortLog(signedBlock.message),
validator = validator.pubKey, validator_index = validator.index.get(), blockRoot = shortLog(blockRoot), validator = shortLog(validator),
deposits = len(signedBlock.message.body.deposits), validator_index = validator.index.get()
attestations = len(signedBlock.message.body.attestations),
graffiti = graffiti
else: else:
warn "Block was not accepted by beacon node", slot = currentSlot, warn "Block was not accepted by beacon node",
validator = validator.pubKey, validator_index = validator.index.get(), blck = shortLog(signedBlock.message),
deposits = len(signedBlock.message.body.deposits), blockRoot = shortLog(blockRoot),
attestations = len(signedBlock.message.body.attestations), validator = shortLog(validator),
graffiti = graffiti validator_index = validator.index.get(),
wall_slot = currentSlot
else: else:
warn "Slashing protection activated for block proposal", warn "Slashing protection activated for block proposal",
slot = currentSlot, validator = validator.pubKey, blck = shortLog(beaconBlock), blockRoot = shortLog(blockRoot),
validator = shortLog(validator),
validator_index = validator.index.get(), validator_index = validator.index.get(),
wall_slot = currentSlot,
existingProposal = notSlashable.error existingProposal = notSlashable.error
except CatchableError as exc: except CatchableError as exc:
error "Unexpected error happens while proposing block", error "Unexpected error happens while proposing block",
@ -87,25 +92,27 @@ proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
let (inFuture, timeToSleep) = vc.beaconClock.fromNow(slot) let (inFuture, timeToSleep) = vc.beaconClock.fromNow(slot)
try: try:
if inFuture: if inFuture:
debug "Proposing block", timeIn = timeToSleep, validator = proposerKey debug "Proposing block", timeIn = timeToSleep,
validator = shortLog(proposerKey)
await sleepAsync(timeToSleep) await sleepAsync(timeToSleep)
else: else:
debug "Proposing block", timeIn = 0.seconds, validator = proposerKey debug "Proposing block", timeIn = 0.seconds,
validator = shortLog(proposerKey)
let sres = vc.getCurrentSlot() let sres = vc.getCurrentSlot()
if sres.isSome(): if sres.isSome():
let currentSlot = sres.get() let currentSlot = sres.get()
# We need to check that we still have validator in our pool. let validator =
let validator = vc.attachedValidators.getValidator(proposerKey) block:
if isNil(validator): let res = vc.getValidator(proposerKey)
debug "Validator is not present in pool anymore, exiting", if res.isNone():
validator = proposerKey
return return
res.get()
await vc.publishBlock(currentSlot, slot, validator) await vc.publishBlock(currentSlot, slot, validator)
except CancelledError: except CancelledError:
debug "Proposing task was cancelled", slot = slot, validator = proposerKey debug "Proposing task was cancelled", slot = slot,
validator = shortLog(proposerKey)
proc spawnProposalTask(vc: ValidatorClientRef, proc spawnProposalTask(vc: ValidatorClientRef,
duty: RestProposerDuty): ProposerTask = duty: RestProposerDuty): ProposerTask =
@ -124,15 +131,36 @@ proc contains(data: openArray[ProposerTask], duty: RestProposerDuty): bool =
return true return true
false false
proc checkDuty(duty: RestProposerDuty, epoch: Epoch, slot: Slot): bool =
let lastSlot = compute_start_slot_at_epoch(epoch + 1'u64)
if duty.slot >= slot:
if duty.slot < lastSlot:
true
else:
warn "Block proposal duty is in the far future, ignoring",
duty_slot = duty.slot, validator = shortLog(duty.pubkey),
wall_slot = slot, last_slot_in_epoch = (lastSlot - 1'u64)
false
else:
warn "Block proposal duty is in the past, ignoring", duty_slot = duty.slot,
validator = shortLog(duty.pubkey), wall_slot = slot
false
proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch, proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
dependentRoot: Eth2Digest, dependentRoot: Eth2Digest,
duties: openArray[RestProposerDuty]) = duties: openArray[RestProposerDuty]) =
let epochDuties = vc.proposers.getOrDefault(epoch) let default = ProposedData(epoch: Epoch(0xFFFF_FFFF_FFFF_FFFF'u64))
let sres = vc.getCurrentSlot()
if sres.isSome():
let
currentSlot = sres.get()
epochDuties = vc.proposers.getOrDefault(epoch, default)
if not(epochDuties.isDefault()): if not(epochDuties.isDefault()):
if epochDuties.dependentRoot != dependentRoot: if epochDuties.dependentRoot != dependentRoot:
warn "Proposer duties re-organization", warn "Proposer duties re-organization", duties_count = len(duties),
wall_slot = currentSlot, epoch = epoch,
prior_dependent_root = epochDuties.dependentRoot, prior_dependent_root = epochDuties.dependentRoot,
dependent_root = dependentRoot dependent_root = dependentRoot, wall_slot = currentSlot
let tasks = let tasks =
block: block:
var res: seq[ProposerTask] var res: seq[ProposerTask]
@ -142,18 +170,21 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
if task notin duties: if task notin duties:
# Task is no more relevant, so cancel it. # Task is no more relevant, so cancel it.
debug "Cancelling running proposal duty task", debug "Cancelling running proposal duty task",
slot = task.duty.slot, validator = task.duty.pubkey slot = task.duty.slot,
validator = shortLog(task.duty.pubkey)
task.future.cancel() task.future.cancel()
else: else:
# If task is already running for proper slot, we keep it alive. # If task is already running for proper slot, we keep it alive.
debug "Keep running previous proposal duty task", debug "Keep running previous proposal duty task",
slot = task.duty.slot, validator = task.duty.pubkey slot = task.duty.slot,
validator = shortLog(task.duty.pubkey)
res.add(task) res.add(task)
for duty in duties: for duty in duties:
if duty notin res: if duty notin res:
debug "New proposal duty received", slot = duty.slot, debug "New proposal duty received", slot = duty.slot,
validator = duty.pubkey validator = shortLog(duty.pubkey)
if checkDuty(duty, epoch, currentSlot):
let task = vc.spawnProposalTask(duty) let task = vc.spawnProposalTask(duty)
if duty.slot in hashset: if duty.slot in hashset:
error "Multiple block proposers for this slot, " & error "Multiple block proposers for this slot, " &
@ -164,6 +195,9 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
res res
vc.proposers[epoch] = ProposedData.init(epoch, dependentRoot, tasks) vc.proposers[epoch] = ProposedData.init(epoch, dependentRoot, tasks)
else: else:
debug "New block proposal duties received",
dependent_root = dependentRoot, duties_count = len(duties),
wall_slot = currentSlot, epoch = epoch
# Spawn new proposer tasks and modify proposers map. # Spawn new proposer tasks and modify proposers map.
let tasks = let tasks =
block: block:
@ -171,7 +205,8 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
var res: seq[ProposerTask] var res: seq[ProposerTask]
for duty in duties: for duty in duties:
debug "New proposal duty received", slot = duty.slot, debug "New proposal duty received", slot = duty.slot,
validator = duty.pubkey validator = shortLog(duty.pubkey)
if checkDuty(duty, epoch, currentSlot):
let task = vc.spawnProposalTask(duty) let task = vc.spawnProposalTask(duty)
if duty.slot in hashset: if duty.slot in hashset:
error "Multiple block proposers for this slot, " & error "Multiple block proposers for this slot, " &

View File

@ -244,3 +244,16 @@ proc getDelay*(vc: ValidatorClientRef, instant: Duration): Duration =
let slotStartTime = currentBeaconTime.slotOrZero().toBeaconTime() let slotStartTime = currentBeaconTime.slotOrZero().toBeaconTime()
let idealTime = Duration(slotStartTime) + instant let idealTime = Duration(slotStartTime) + instant
currentTime - idealTime currentTime - idealTime
proc getValidator*(vc: ValidatorClientRef,
key: ValidatorPubkey): Option[AttachedValidator] =
let validator = vc.attachedValidators.getValidator(key)
if isNil(validator):
warn "Validator not in pool anymore", validator = shortLog(validator)
none[AttachedValidator]()
else:
if validator.index.isNone():
warn "Validator index is missing", validator = shortLog(validator)
none[AttachedValidator]()
else:
some(validator)

View File

@ -48,8 +48,12 @@ proc pollForValidatorIndices*(vc: ValidatorClientRef) {.async.} =
let res = let res =
try: try:
await vc.getValidators(idents) await vc.getValidators(idents)
except ValidatorApiError as exc: except ValidatorApiError:
error "Unable to retrieve head state's validator information" error "Unable to get head state's validator information"
return
except CatchableError as exc:
error "Unexpected error occurred while getting validator information",
err_name = exc.name, err_msg = exc.msg
return return
for item in res: for item in res:
@ -94,8 +98,12 @@ proc pollForAttesterDuties*(vc: ValidatorClientRef,
let res = let res =
try: try:
await vc.getAttesterDuties(epoch, indices) await vc.getAttesterDuties(epoch, indices)
except ValidatorApiError as exc: except ValidatorApiError:
error "Unable to retrieve attester duties", epoch = epoch error "Unable to get attester duties", epoch = epoch
return 0
except CatchableError as exc:
error "Unexpected error occured while getting attester duties",
epoch = epoch, err_name = exc.name, err_msg = exc.msg
return 0 return 0
if currentRoot.isNone(): if currentRoot.isNone():
@ -264,9 +272,13 @@ proc pollForBeaconProposers*(vc: ValidatorClientRef) {.async.} =
else: else:
debug "No relevant proposer duties received", slot = currentSlot, debug "No relevant proposer duties received", slot = currentSlot,
duties_count = len(duties) duties_count = len(duties)
except ValidatorApiError as exc: except ValidatorApiError:
debug "Unable to retrieve proposer duties", slot = currentSlot, debug "Unable to get proposer duties", slot = currentSlot,
epoch = currentEpoch epoch = currentEpoch
except CatchableError as exc:
debug "Unexpected error occured while getting proposer duties",
slot = currentSlot, epoch = currentEpoch, err_name = exc.name,
err_msg = exc.msg
vc.pruneBeaconProposers(currentEpoch) vc.pruneBeaconProposers(currentEpoch)

View File

@ -10,6 +10,10 @@ proc pollForFork(vc: ValidatorClientRef) {.async.} =
except ValidatorApiError as exc: except ValidatorApiError as exc:
error "Unable to retrieve head state's fork", reason = exc.msg error "Unable to retrieve head state's fork", reason = exc.msg
return return
except CatchableError as exc:
error "Unexpected error occured while getting fork information",
err_name = exc.name, err_msg = exc.msg
return
if vc.fork.isNone() or vc.fork.get() != fork: if vc.fork.isNone() or vc.fork.get() != fork:
vc.fork = some(fork) vc.fork = some(fork)