Various fixes for VC and BN REST server. (#4673)

* Fix issue when VC unable to detect errors properly and act accordingly.
Switch all API functions used by VC to RestPlainResponse, this allows us to print errors returned by BN servers.

* Fix issue when prepareBeaconCommitteeSubnet() do not perform actions when BN is optimistically synced only.

* Fix Defect issue.

* Fix submit/publish returning `false` when operation was successful.

* Address review comments.

* Fix some client calls unable to receive `execution_optimistic` field, mark BN as OptSynced when such request has been made.

* Adjust warning levels.

---------

Co-authored-by: Jacek Sieka <jacek@status.im>
This commit is contained in:
Eugene Kabanov 2023-03-03 22:20:01 +02:00 committed by GitHub
parent fec580c39c
commit c8b50765cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1152 additions and 872 deletions

View File

@ -641,7 +641,8 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
InvalidSubscriptionRequestValueError,
$dres.error())
dres.get()
if node.isSynced(node.dag.head) != SyncStatus.synced:
if node.isSynced(node.dag.head) == SyncStatus.unsynced:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
let

View File

@ -114,6 +114,7 @@ type
DataEnclosedObject |
DataMetaEnclosedObject |
DataRootEnclosedObject |
DataOptimisticObject |
DataVersionEnclosedObject |
GetBlockV2Response |
GetDistributedKeystoresResponse |

View File

@ -56,6 +56,14 @@ proc getStateValidators*(state_id: StateIdent,
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators
proc getStateValidatorsPlain*(
state_id: StateIdent,
id: seq[ValidatorIdent]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/validators",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators
proc getStateValidator*(state_id: StateIdent,
validator_id: ValidatorIdent
): RestResponse[GetStateValidatorResponse] {.
@ -224,6 +232,11 @@ proc getBlockRoot*(block_id: BlockIdent): RestResponse[GetBlockRootResponse] {.
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getBlockRoot
proc getBlockRootPlain*(block_id: BlockIdent): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/blocks/{block_id}/root",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getBlockRoot
proc getBlockAttestations*(block_id: BlockIdent
): RestResponse[GetBlockAttestationsResponse] {.
rest, endpoint: "/eth/v1/beacon/blocks/{block_id}/attestations",

View File

@ -16,6 +16,10 @@ proc getForkSchedule*(): RestResponse[GetForkScheduleResponse] {.
rest, endpoint: "/eth/v1/config/fork_schedule", meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Config/getForkSchedule
proc getForkSchedulePlain*(): RestPlainResponse {.
rest, endpoint: "/eth/v1/config/fork_schedule", meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Config/getForkSchedule
proc getSpec*(): RestResponse[GetSpecResponse] {.
rest, endpoint: "/eth/v1/config/spec", meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Config/getSpec

View File

@ -509,6 +509,11 @@ type
DataRootEnclosedObject*[T] = object
dependent_root*: Eth2Digest
data*: T
execution_optimistic*: Option[bool]
DataOptimisticObject*[T] = object
data*: T
execution_optimistic*: Option[bool]
ForkedSignedBlockHeader* = object
message*: uint32 # message offset
@ -613,10 +618,6 @@ type
RestRoot* = object
root*: Eth2Digest
DataRestRoot* = object
execution_optimistic*: Option[bool]
data*: RestRoot
# Types based on the OAPI yaml file - used in responses to requests
GetBeaconHeadResponse* = DataEnclosedObject[Slot]
GetAggregatedAttestationResponse* = DataEnclosedObject[Attestation]
@ -624,7 +625,7 @@ type
GetBlockAttestationsResponse* = DataEnclosedObject[seq[Attestation]]
GetBlockHeaderResponse* = DataEnclosedObject[RestBlockHeaderInfo]
GetBlockHeadersResponse* = DataEnclosedObject[seq[RestBlockHeaderInfo]]
GetBlockRootResponse* = DataRestRoot
GetBlockRootResponse* = DataOptimisticObject[RestRoot]
GetDebugChainHeadsResponse* = DataEnclosedObject[seq[RestChainHead]]
GetDepositContractResponse* = DataEnclosedObject[RestDepositContract]
GetDepositSnapshotResponse* = DataEnclosedObject[RestDepositSnapshot]
@ -646,11 +647,11 @@ type
GetSpecVCResponse* = DataEnclosedObject[RestSpecVC]
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
GetStateForkResponse* = DataEnclosedObject[Fork]
GetStateRootResponse* = DataRestRoot
GetStateRootResponse* = DataOptimisticObject[RestRoot]
GetStateValidatorBalancesResponse* = DataEnclosedObject[seq[RestValidatorBalance]]
GetStateValidatorResponse* = DataEnclosedObject[RestValidator]
GetStateValidatorsResponse* = DataEnclosedObject[seq[RestValidator]]
GetSyncCommitteeDutiesResponse* = DataEnclosedObject[seq[RestSyncCommitteeDuty]]
GetStateValidatorsResponse* = DataOptimisticObject[seq[RestValidator]]
GetSyncCommitteeDutiesResponse* = DataOptimisticObject[seq[RestSyncCommitteeDuty]]
GetSyncingStatusResponse* = DataEnclosedObject[RestSyncInfo]
GetVersionResponse* = DataEnclosedObject[RestNodeVersion]
GetEpochSyncCommitteesResponse* = DataEnclosedObject[RestEpochSyncCommittee]

View File

@ -12,72 +12,155 @@ import
export chronos, client, rest_types, eth2_rest_serialization
proc getAttesterDuties*(epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[GetAttesterDutiesResponse] {.
proc getAttesterDuties*(
epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[GetAttesterDutiesResponse] {.
rest, endpoint: "/eth/v1/validator/duties/attester/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getAttesterDuties
proc getProposerDuties*(epoch: Epoch): RestResponse[GetProposerDutiesResponse] {.
proc getAttesterDutiesPlain*(
epoch: Epoch,
body: seq[ValidatorIndex]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/duties/attester/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getAttesterDuties
proc getProposerDuties*(
epoch: Epoch
): RestResponse[GetProposerDutiesResponse] {.
rest, endpoint: "/eth/v1/validator/duties/proposer/{epoch}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getProposerDuties
proc getSyncCommitteeDuties*(epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[GetSyncCommitteeDutiesResponse] {.
proc getProposerDutiesPlain*(
epoch: Epoch
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/duties/proposer/{epoch}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getProposerDuties
proc getSyncCommitteeDuties*(
epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[GetSyncCommitteeDutiesResponse] {.
rest, endpoint: "/eth/v1/validator/duties/sync/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getSyncCommitteeDuties
proc produceBlockV2*(slot: Slot, randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[ProduceBlockResponseV2] {.
rest, endpoint: "/eth/v2/validator/blocks/{slot}",
meth: MethodGet.}
proc getSyncCommitteeDutiesPlain*(
epoch: Epoch,
body: seq[ValidatorIndex]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/duties/sync/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getSyncCommitteeDuties
proc produceBlockV2*(
slot: Slot,
randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[ProduceBlockResponseV2] {.
rest, endpoint: "/eth/v2/validator/blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlockV2
proc produceBlindedBlock*(slot: Slot, randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[ProduceBlindedBlockResponse] {.
rest, endpoint: "/eth/v1/validator/blinded_blocks/{slot}",
meth: MethodGet.}
proc produceBlockV2Plain*(
slot: Slot,
randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestPlainResponse {.
rest, endpoint: "/eth/v2/validator/blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlockV2
proc produceBlindedBlock*(
slot: Slot,
randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[ProduceBlindedBlockResponse] {.
rest, endpoint: "/eth/v1/validator/blinded_blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlindedBlock
proc produceAttestationData*(slot: Slot,
committee_index: CommitteeIndex
): RestResponse[ProduceAttestationDataResponse] {.
proc produceBlindedBlockPlain*(
slot: Slot,
randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/blinded_blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlindedBlock
proc produceAttestationData*(
slot: Slot,
committee_index: CommitteeIndex
): RestResponse[ProduceAttestationDataResponse] {.
rest, endpoint: "/eth/v1/validator/attestation_data",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceAttestationData
proc getAggregatedAttestation*(attestation_data_root: Eth2Digest,
slot: Slot): RestResponse[GetAggregatedAttestationResponse] {.
proc produceAttestationDataPlain*(
slot: Slot,
committee_index: CommitteeIndex
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/attestation_data",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceAttestationData
proc getAggregatedAttestation*(
attestation_data_root: Eth2Digest,
slot: Slot
): RestResponse[GetAggregatedAttestationResponse] {.
rest, endpoint: "/eth/v1/validator/aggregate_attestation"
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getAggregatedAttestation
proc publishAggregateAndProofs*(body: seq[SignedAggregateAndProof]
): RestPlainResponse {.
proc getAggregatedAttestationPlain*(
attestation_data_root: Eth2Digest,
slot: Slot
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/aggregate_attestation"
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/getAggregatedAttestation
proc publishAggregateAndProofs*(
body: seq[SignedAggregateAndProof]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/aggregate_and_proofs",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/publishAggregateAndProofs
proc prepareBeaconCommitteeSubnet*(body: seq[RestCommitteeSubscription]): RestPlainResponse {.
proc prepareBeaconCommitteeSubnet*(
body: seq[RestCommitteeSubscription]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/beacon_committee_subscriptions",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/prepareBeaconCommitteeSubnet
proc prepareSyncCommitteeSubnets*(body: seq[RestSyncCommitteeSubscription]): RestPlainResponse {.
proc prepareSyncCommitteeSubnets*(
body: seq[RestSyncCommitteeSubscription]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/sync_committee_subscriptions",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/prepareSyncCommitteeSubnets
proc produceSyncCommitteeContribution*(slot: Slot,
subcommittee_index: SyncSubcommitteeIndex,
beacon_block_root: Eth2Digest
): RestResponse[ProduceSyncCommitteeContributionResponse] {.
proc produceSyncCommitteeContribution*(
slot: Slot,
subcommittee_index: SyncSubcommitteeIndex,
beacon_block_root: Eth2Digest
): RestResponse[ProduceSyncCommitteeContributionResponse] {.
rest, endpoint: "/eth/v1/validator/sync_committee_contribution",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceSyncCommitteeContribution
proc produceSyncCommitteeContributionPlain*(
slot: Slot,
subcommittee_index: SyncSubcommitteeIndex,
beacon_block_root: Eth2Digest
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/sync_committee_contribution",
meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Validator/produceSyncCommitteeContribution

File diff suppressed because it is too large Load Diff

View File

@ -57,8 +57,8 @@ proc serveAttestation(service: AttestationServiceRef, adata: AttestationData,
let res = await validator.getAttestationSignature(
fork, vc.beaconGenesis.genesis_validators_root, adata)
if res.isErr():
error "Unable to sign attestation", validator = shortLog(validator),
error_msg = res.error()
warn "Unable to sign attestation", validator = shortLog(validator),
error_msg = res.error()
return false
res.get()
except CancelledError as exc:
@ -84,11 +84,11 @@ proc serveAttestation(service: AttestationServiceRef, adata: AttestationData,
try:
await vc.submitPoolAttestations(@[attestation], ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish attestation",
attestation = shortLog(attestation),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
warn "Unable to publish attestation",
attestation = shortLog(attestation),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
return false
except CancelledError as exc:
debug "Attestation publishing process was interrupted"
@ -135,10 +135,10 @@ proc serveAggregateAndProof*(service: AttestationServiceRef,
let res = await validator.getAggregateAndProofSignature(
fork, genesisRoot, proof)
if res.isErr():
error "Unable to sign aggregate and proof using remote signer",
validator = shortLog(validator),
attestation = shortLog(proof.aggregate),
error_msg = res.error()
warn "Unable to sign aggregate and proof using remote signer",
validator = shortLog(validator),
attestation = shortLog(proof.aggregate),
error_msg = res.error()
return false
res.get()
except CancelledError as exc:
@ -166,11 +166,11 @@ proc serveAggregateAndProof*(service: AttestationServiceRef,
try:
await vc.publishAggregateAndProofs(@[signedProof], ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish aggregated attestation",
attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
warn "Unable to publish aggregated attestation",
attestation = shortLog(signedProof.message.aggregate),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
return false
except CancelledError as exc:
debug "Publish aggregate and proofs request was interrupted"
@ -215,11 +215,11 @@ proc produceAndPublishAttestations*(service: AttestationServiceRef,
debug "Serving attestation duty", duty = duty.data, epoch = slot.epoch()
if (duty.data.slot != ad.slot) or
(uint64(duty.data.committee_index) != ad.index):
error "Inconsistent validator duties during attestation signing",
validator = shortLog(duty.data.pubkey),
duty_slot = duty.data.slot,
duty_index = duty.data.committee_index,
attestation_slot = ad.slot, attestation_index = ad.index
warn "Inconsistent validator duties during attestation signing",
validator = shortLog(duty.data.pubkey),
duty_slot = duty.data.slot,
duty_index = duty.data.committee_index,
attestation_slot = ad.slot, attestation_index = ad.index
continue
res.add(service.serveAttestation(ad, duty))
res
@ -273,10 +273,10 @@ proc produceAndPublishAggregates(service: AttestationServiceRef,
if (duty.data.slot != slot) or
(duty.data.committee_index != committeeIndex):
error "Inconsistent validator duties during aggregate signing",
duty_slot = duty.data.slot, slot = slot,
duty_committee_index = duty.data.committee_index,
committee_index = committeeIndex
warn "Inconsistent validator duties during aggregate signing",
duty_slot = duty.data.slot, slot = slot,
duty_committee_index = duty.data.committee_index,
committee_index = committeeIndex
continue
if duty.slotSig.isSome():
let slotSignature = duty.slotSig.get()
@ -294,9 +294,9 @@ proc produceAndPublishAggregates(service: AttestationServiceRef,
await vc.getAggregatedAttestation(slot, attestationRoot,
ApiStrategyKind.Best)
except ValidatorApiError as exc:
error "Unable to get aggregated attestation data", slot = slot,
attestation_root = shortLog(attestationRoot),
reason = exc.getFailureReason()
warn "Unable to get aggregated attestation data", slot = slot,
attestation_root = shortLog(attestationRoot),
reason = exc.getFailureReason()
return
except CancelledError as exc:
debug "Aggregated attestation request was interrupted"
@ -368,9 +368,9 @@ proc publishAttestationsAndAggregates(service: AttestationServiceRef,
try:
await service.produceAndPublishAttestations(slot, committee_index, duties)
except ValidatorApiError as exc:
error "Unable to proceed attestations", slot = slot,
committee_index = committee_index, duties_count = len(duties),
reason = exc.getFailureReason()
warn "Unable to proceed attestations", slot = slot,
committee_index = committee_index, duties_count = len(duties),
reason = exc.getFailureReason()
return
except CancelledError as exc:
debug "Publish attestation request was interrupted"

View File

@ -39,10 +39,10 @@ proc produceBlock(
await vc.produceBlockV2(slot, randao_reveal, graffiti,
ApiStrategyKind.Best)
except ValidatorApiError as exc:
error "Unable to retrieve block data", reason = exc.getFailureReason()
warn "Unable to retrieve block data", reason = exc.getFailureReason()
return Opt.none(PreparedBeaconBlock)
except CancelledError as exc:
error "Block data production has been interrupted"
debug "Block data production has been interrupted"
raise exc
except CatchableError as exc:
error "An unexpected error occurred while getting block data",
@ -69,11 +69,11 @@ proc produceBlindedBlock(
await vc.produceBlindedBlock(slot, randao_reveal, graffiti,
ApiStrategyKind.Best)
except ValidatorApiError as exc:
error "Unable to retrieve blinded block data", error_msg = exc.msg,
reason = exc.getFailureReason()
warn "Unable to retrieve blinded block data", error_msg = exc.msg,
reason = exc.getFailureReason()
return Opt.none(PreparedBlindedBeaconBlock)
except CancelledError as exc:
error "Blinded block data production has been interrupted"
debug "Blinded block data production has been interrupted"
raise exc
except CatchableError as exc:
error "An unexpected error occurred while getting blinded block data",
@ -115,12 +115,12 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
try:
let res = await validator.getEpochSignature(fork, genesisRoot, slot.epoch)
if res.isErr():
error "Unable to generate randao reveal using remote signer",
error_msg = res.error()
warn "Unable to generate randao reveal using remote signer",
reason = res.error()
return
res.get()
except CancelledError as exc:
error "Randao reveal production has been interrupted"
debug "Randao reveal production has been interrupted"
raise exc
except CatchableError as exc:
error "An unexpected error occurred while receiving randao data",
@ -193,8 +193,8 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
preparedBlock.blockRoot,
preparedBlock.data)
if res.isErr():
error "Unable to sign blinded block proposal using remote signer",
error_msg = res.error()
warn "Unable to sign blinded block proposal using remote signer",
reason = res.error()
return
res.get()
except CancelledError as exc:
@ -216,8 +216,8 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
debug "Sending blinded block"
await vc.publishBlindedBlock(signedBlock, ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish blinded block",
reason = exc.getFailureReason()
warn "Unable to publish blinded block",
reason = exc.getFailureReason()
return
except CancelledError as exc:
debug "Blinded block publication has been interrupted"
@ -259,8 +259,8 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
preparedBlock.blockRoot,
preparedBlock.data)
if res.isErr():
error "Unable to sign block proposal using remote signer",
error_msg = res.error()
warn "Unable to sign block proposal using remote signer",
reason = res.error()
return
res.get()
except CancelledError as exc:
@ -278,7 +278,7 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
debug "Sending block"
await vc.publishBlock(signedBlock, ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish block", reason = exc.getFailureReason()
warn "Unable to publish block", reason = exc.getFailureReason()
return
except CancelledError as exc:
debug "Block publication has been interrupted"
@ -394,8 +394,8 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
if checkDuty(duty, epoch, currentSlot):
let task = vc.spawnProposalTask(duty)
if duty.slot in hashset:
error "Multiple block proposers for this slot, " &
"producing blocks for all proposers", slot = duty.slot
warn "Multiple block proposers for this slot, " &
"producing blocks for all proposers", slot = duty.slot
else:
hashset.incl(duty.slot)
res.add(task)
@ -416,8 +416,8 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
if checkDuty(duty, epoch, currentSlot):
let task = vc.spawnProposalTask(duty)
if duty.slot in hashset:
error "Multiple block proposers for this slot, " &
"producing blocks for all proposers", slot = duty.slot
warn "Multiple block proposers for this slot, " &
"producing blocks for all proposers", slot = duty.slot
else:
hashset.incl(duty.slot)
res.add(task)

View File

@ -133,7 +133,9 @@ type
Compatible, ## BN configuration is compatible with VC configuration.
NotSynced, ## BN is not in sync.
OptSynced, ## BN is optimistically synced (EL is not in sync).
Synced ## BN and EL are synced.
Synced, ## BN and EL are synced.
Unexpected, ## BN sends unexpected/incorrect response.
InternalError ## BN reports internal error.
BeaconNodesCounters* = object
data*: array[int(high(RestBeaconNodeStatus)) + 1, int]
@ -251,6 +253,8 @@ proc `$`*(status: RestBeaconNodeStatus): string =
of RestBeaconNodeStatus.NotSynced: "bn-unsynced"
of RestBeaconNodeStatus.OptSynced: "el-unsynced"
of RestBeaconNodeStatus.Synced: "synced"
of RestBeaconNodeStatus.Unexpected: "unexpected data"
of RestBeaconNodeStatus.InternalError: "internal error"
proc `$`*(failure: ApiFailure): string =
case failure
@ -344,6 +348,87 @@ chronicles.expandIt(SyncCommitteeDuty):
validator_index = it.validator_index
validator_sync_committee_index = it.validator_sync_committee_index
proc checkConfig*(info: RestSpecVC): bool =
# /!\ Keep in sync with `spec/eth2_apis/rest_types.nim` > `RestSpecVC`.
info.MAX_VALIDATORS_PER_COMMITTEE == MAX_VALIDATORS_PER_COMMITTEE and
info.SLOTS_PER_EPOCH == SLOTS_PER_EPOCH and
info.SECONDS_PER_SLOT == SECONDS_PER_SLOT and
info.EPOCHS_PER_ETH1_VOTING_PERIOD == EPOCHS_PER_ETH1_VOTING_PERIOD and
info.SLOTS_PER_HISTORICAL_ROOT == SLOTS_PER_HISTORICAL_ROOT and
info.EPOCHS_PER_HISTORICAL_VECTOR == EPOCHS_PER_HISTORICAL_VECTOR and
info.EPOCHS_PER_SLASHINGS_VECTOR == EPOCHS_PER_SLASHINGS_VECTOR and
info.HISTORICAL_ROOTS_LIMIT == HISTORICAL_ROOTS_LIMIT and
info.VALIDATOR_REGISTRY_LIMIT == VALIDATOR_REGISTRY_LIMIT and
info.MAX_PROPOSER_SLASHINGS == MAX_PROPOSER_SLASHINGS and
info.MAX_ATTESTER_SLASHINGS == MAX_ATTESTER_SLASHINGS and
info.MAX_ATTESTATIONS == MAX_ATTESTATIONS and
info.MAX_DEPOSITS == MAX_DEPOSITS and
info.MAX_VOLUNTARY_EXITS == MAX_VOLUNTARY_EXITS and
info.DOMAIN_BEACON_PROPOSER == DOMAIN_BEACON_PROPOSER and
info.DOMAIN_BEACON_ATTESTER == DOMAIN_BEACON_ATTESTER and
info.DOMAIN_RANDAO == DOMAIN_RANDAO and
info.DOMAIN_DEPOSIT == DOMAIN_DEPOSIT and
info.DOMAIN_VOLUNTARY_EXIT == DOMAIN_VOLUNTARY_EXIT and
info.DOMAIN_SELECTION_PROOF == DOMAIN_SELECTION_PROOF and
info.DOMAIN_AGGREGATE_AND_PROOF == DOMAIN_AGGREGATE_AND_PROOF
proc updateStatus*(node: BeaconNodeServerRef, status: RestBeaconNodeStatus) =
logScope:
endpoint = node
case status
of RestBeaconNodeStatus.Offline:
if node.status != status:
warn "Beacon node down"
node.status = status
of RestBeaconNodeStatus.Online:
if node.status != status:
let version = if node.ident.isSome(): node.ident.get() else: "<missing>"
notice "Beacon node is online", agent_version = version
node.status = status
of RestBeaconNodeStatus.Incompatible:
if node.status != status:
warn "Beacon node has incompatible configuration"
node.status = status
of RestBeaconNodeStatus.Compatible:
if node.status != status:
notice "Beacon node is compatible"
node.status = status
of RestBeaconNodeStatus.NotSynced:
if node.status notin {RestBeaconNodeStatus.NotSynced,
RestBeaconNodeStatus.OptSynced}:
doAssert(node.syncInfo.isSome())
let si = node.syncInfo.get()
warn "Beacon node not in sync",
last_head_slot = si.head_slot,
last_sync_distance = si.sync_distance,
last_optimistic = si.is_optimistic.get(false)
node.status = status
of RestBeaconNodeStatus.OptSynced:
if node.status != status:
doAssert(node.syncInfo.isSome())
let si = node.syncInfo.get()
notice "Execution client not in sync (beacon node optimistically synced)",
last_head_slot = si.head_slot,
last_sync_distance = si.sync_distance,
last_optimistic = si.is_optimistic.get(false)
node.status = status
of RestBeaconNodeStatus.Synced:
if node.status != status:
doAssert(node.syncInfo.isSome())
let si = node.syncInfo.get()
notice "Beacon node is in sync",
head_slot = si.head_slot, sync_distance = si.sync_distance,
is_optimistic = si.is_optimistic.get(false)
node.status = status
of RestBeaconNodeStatus.Unexpected:
if node.status != status:
error "Beacon node provides unexpected response"
node.status = status
of RestBeaconNodeStatus.InternalError:
if node.status != status:
warn "Beacon node reports internal error"
node.status = status
proc stop*(csr: ClientServiceRef) {.async.} =
debug "Stopping service", service = csr.name
if csr.state == ServiceState.Running:

View File

@ -66,7 +66,7 @@ proc pollForValidatorIndices*(vc: ValidatorClientRef) {.async.} =
try:
await vc.getValidators(idents, ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to get head state's validator information",
warn "Unable to get head state's validator information",
reason = exc.getFailureReason()
return
except CancelledError as exc:
@ -140,8 +140,8 @@ proc pollForAttesterDuties*(vc: ValidatorClientRef,
try:
await vc.getAttesterDuties(epoch, indices, ApiStrategyKind.First)
except ValidatorApiError as exc:
notice "Unable to get attester duties", epoch = epoch,
reason = exc.getFailureReason()
warn "Unable to get attester duties", epoch = epoch,
reason = exc.getFailureReason()
return 0
except CancelledError as exc:
debug "Attester duties processing was interrupted"
@ -225,7 +225,7 @@ proc pollForAttesterDuties*(vc: ValidatorClientRef,
if fut.done():
let sigRes = fut.read()
if sigRes.isErr():
error "Unable to create slot signature using remote signer",
warn "Unable to create slot signature using remote signer",
validator = shortLog(validators[index]),
error_msg = sigRes.error()
DutyAndProof.init(item.epoch, currentRoot.get(), item.duty,
@ -274,8 +274,8 @@ proc pollForSyncCommitteeDuties*(vc: ValidatorClientRef,
try:
await vc.getSyncCommitteeDuties(epoch, indices, ApiStrategyKind.First)
except ValidatorApiError as exc:
notice "Unable to get sync committee duties", epoch = epoch,
reason = exc.getFailureReason()
warn "Unable to get sync committee duties", epoch = epoch,
reason = exc.getFailureReason()
return 0
except CancelledError as exc:
debug "Sync committee duties processing was interrupted"
@ -397,9 +397,9 @@ proc pollForAttesterDuties*(vc: ValidatorClientRef) {.async.} =
if len(subscriptions) > 0:
let res = await vc.prepareBeaconCommitteeSubnet(subscriptions)
if res == 0:
error "Failed to subscribe validators to beacon committee subnets",
slot = currentSlot, epoch = currentEpoch,
subscriptions_count = len(subscriptions)
warn "Failed to subscribe validators to beacon committee subnets",
slot = currentSlot, epoch = currentEpoch,
subscriptions_count = len(subscriptions)
vc.pruneAttesterDuties(currentEpoch)
@ -468,9 +468,9 @@ proc pollForSyncCommitteeDuties* (vc: ValidatorClientRef) {.async.} =
if len(subscriptions) > 0:
let res = await vc.prepareSyncCommitteeSubnets(subscriptions)
if res != 0:
error "Failed to subscribe validators to sync committee subnets",
slot = currentSlot, epoch = currentEpoch,
subscriptions_count = len(subscriptions)
warn "Failed to subscribe validators to sync committee subnets",
slot = currentSlot, epoch = currentEpoch,
subscriptions_count = len(subscriptions)
vc.pruneSyncCommitteeDuties(currentSlot)
@ -506,8 +506,8 @@ proc pollForBeaconProposers*(vc: ValidatorClientRef) {.async.} =
debug "No relevant proposer duties received", slot = currentSlot,
duties_count = len(duties)
except ValidatorApiError as exc:
notice "Unable to get proposer duties", slot = currentSlot,
epoch = currentEpoch, reason = exc.getFailureReason()
warn "Unable to get proposer duties", slot = currentSlot,
epoch = currentEpoch, reason = exc.getFailureReason()
except CancelledError as exc:
debug "Proposer duties processing was interrupted"
raise exc

View File

@ -113,31 +113,12 @@ proc checkCompatible(
error_message = exc.msg
return RestBeaconNodeStatus.Offline
let genesisFlag = (genesis != vc.beaconGenesis)
let configFlag =
# /!\ Keep in sync with `spec/eth2_apis/rest_types.nim` > `RestSpecVC`.
info.MAX_VALIDATORS_PER_COMMITTEE != MAX_VALIDATORS_PER_COMMITTEE or
info.SLOTS_PER_EPOCH != SLOTS_PER_EPOCH or
info.SECONDS_PER_SLOT != SECONDS_PER_SLOT or
info.EPOCHS_PER_ETH1_VOTING_PERIOD != EPOCHS_PER_ETH1_VOTING_PERIOD or
info.SLOTS_PER_HISTORICAL_ROOT != SLOTS_PER_HISTORICAL_ROOT or
info.EPOCHS_PER_HISTORICAL_VECTOR != EPOCHS_PER_HISTORICAL_VECTOR or
info.EPOCHS_PER_SLASHINGS_VECTOR != EPOCHS_PER_SLASHINGS_VECTOR or
info.HISTORICAL_ROOTS_LIMIT != HISTORICAL_ROOTS_LIMIT or
info.VALIDATOR_REGISTRY_LIMIT != VALIDATOR_REGISTRY_LIMIT or
info.MAX_PROPOSER_SLASHINGS != MAX_PROPOSER_SLASHINGS or
info.MAX_ATTESTER_SLASHINGS != MAX_ATTESTER_SLASHINGS or
info.MAX_ATTESTATIONS != MAX_ATTESTATIONS or
info.MAX_DEPOSITS != MAX_DEPOSITS or
info.MAX_VOLUNTARY_EXITS != MAX_VOLUNTARY_EXITS or
info.DOMAIN_BEACON_PROPOSER != DOMAIN_BEACON_PROPOSER or
info.DOMAIN_BEACON_ATTESTER != DOMAIN_BEACON_ATTESTER or
info.DOMAIN_RANDAO != DOMAIN_RANDAO or
info.DOMAIN_DEPOSIT != DOMAIN_DEPOSIT or
info.DOMAIN_VOLUNTARY_EXIT != DOMAIN_VOLUNTARY_EXIT or
info.DOMAIN_SELECTION_PROOF != DOMAIN_SELECTION_PROOF or
info.DOMAIN_AGGREGATE_AND_PROOF != DOMAIN_AGGREGATE_AND_PROOF
let
genesisFlag = (genesis != vc.beaconGenesis)
configFlag = not(checkConfig(info))
node.config = some(info)
node.genesis = some(genesis)
let res =
if configFlag or genesisFlag:
if node.status != RestBeaconNodeStatus.Incompatible:
@ -145,10 +126,6 @@ proc checkCompatible(
genesis_flag = genesisFlag, config_flag = configFlag
RestBeaconNodeStatus.Incompatible
else:
if node.status != RestBeaconNodeStatus.Compatible:
debug "Beacon node has compatible configuration"
node.config = some(info)
node.genesis = some(genesis)
RestBeaconNodeStatus.Compatible
return res
@ -186,23 +163,10 @@ proc checkSync(
if not(syncInfo.is_syncing) or (syncInfo.sync_distance < SYNC_TOLERANCE):
if not(syncInfo.is_optimistic.get(false)):
if node.status != RestBeaconNodeStatus.Synced:
info "Beacon node is in sync",
sync_distance = syncInfo.sync_distance,
head_slot = syncInfo.head_slot, is_optimistic = optimistic
RestBeaconNodeStatus.Synced
else:
if node.status != RestBeaconNodeStatus.OptSynced:
info "Execution client not in sync " &
"(beacon node optimistically synced)",
sync_distance = syncInfo.sync_distance,
head_slot = syncInfo.head_slot, is_optimistic = optimistic
RestBeaconNodeStatus.OptSynced
else:
if node.status != RestBeaconNodeStatus.NotSynced:
warn "Beacon node not in sync",
sync_distance = syncInfo.sync_distance,
head_slot = syncInfo.head_slot, is_optimistic = optimistic
RestBeaconNodeStatus.NotSynced
return res
@ -219,17 +183,14 @@ proc checkOnline(
debug "Status request was interrupted"
raise exc
except RestError as exc:
if node.status != RestBeaconNodeStatus.Offline:
debug "Unable to check beacon node's status",
error_name = exc.name, error_message = exc.msg
debug "Unable to check beacon node's status",
error_name = exc.name, error_message = exc.msg
return RestBeaconNodeStatus.Offline
except CatchableError as exc:
if node.status != RestBeaconNodeStatus.Offline:
error "Unexpected exception", error_name = exc.name,
error_message = exc.msg
error "Unexpected exception", error_name = exc.name,
error_message = exc.msg
return RestBeaconNodeStatus.Offline
if node.status != RestBeaconNodeStatus.Online:
debug "Beacon node has been identified", agent = agent.version
node.ident = some(agent.version)
return RestBeaconNodeStatus.Online
proc checkNode(vc: ValidatorClientRef,
@ -237,28 +198,34 @@ proc checkNode(vc: ValidatorClientRef,
let nstatus = node.status
debug "Checking beacon node", endpoint = node, status = node.status
if nstatus in {RestBeaconNodeStatus.Offline}:
if nstatus in {RestBeaconNodeStatus.Offline,
RestBeaconNodeStatus.Unexpected,
RestBeaconNodeStatus.InternalError}:
let status = await node.checkOnline()
node.status = status
node.updateStatus(status)
if status != RestBeaconNodeStatus.Online:
return nstatus != status
if nstatus in {RestBeaconNodeStatus.Offline,
RestBeaconNodeStatus.Unexpected,
RestBeaconNodeStatus.InternalError,
RestBeaconNodeStatus.Online,
RestBeaconNodeStatus.Incompatible}:
let status = await vc.checkCompatible(node)
node.status = status
node.updateStatus(status)
if status != RestBeaconNodeStatus.Compatible:
return nstatus != status
if nstatus in {RestBeaconNodeStatus.Offline,
RestBeaconNodeStatus.Unexpected,
RestBeaconNodeStatus.InternalError,
RestBeaconNodeStatus.Online,
RestBeaconNodeStatus.Incompatible,
RestBeaconNodeStatus.Compatible,
RestBeaconNodeStatus.OptSynced,
RestBeaconNodeStatus.NotSynced}:
let status = await vc.checkSync(node)
node.status = status
node.updateStatus(status)
return nstatus != status
proc checkNodes*(service: FallbackServiceRef): Future[bool] {.async.} =
@ -298,8 +265,8 @@ proc mainLoop(service: FallbackServiceRef) {.async.} =
debug "Service interrupted"
true
except CatchableError as exc:
warn "Service crashed with unexpected error", err_name = exc.name,
err_msg = exc.msg
error "Service crashed with unexpected error", err_name = exc.name,
err_msg = exc.msg
true
if breakLoop:

View File

@ -53,8 +53,8 @@ proc pollForFork(vc: ValidatorClientRef) {.async.} =
try:
await vc.getForkSchedule(ApiStrategyKind.Best)
except ValidatorApiError as exc:
error "Unable to retrieve fork schedule",
reason = exc.getFailureReason(), err_msg = exc.msg
warn "Unable to retrieve fork schedule",
reason = exc.getFailureReason(), err_msg = exc.msg
return
except CancelledError as exc:
debug "Fork retrieval process was interrupted"
@ -68,7 +68,7 @@ proc pollForFork(vc: ValidatorClientRef) {.async.} =
block:
let res = sortForks(forks)
if res.isErr():
error "Invalid fork schedule received", reason = res.error()
warn "Invalid fork schedule received", reason = res.error()
return
res.get()

View File

@ -44,9 +44,9 @@ proc serveSyncCommitteeMessage*(service: SyncCommitteeServiceRef,
genesisValidatorsRoot,
slot, beaconBlockRoot)
if res.isErr():
error "Unable to sign committee message using remote signer",
validator = shortLog(validator), slot = slot,
block_root = shortLog(beaconBlockRoot)
warn "Unable to sign committee message using remote signer",
validator = shortLog(validator), slot = slot,
block_root = shortLog(beaconBlockRoot)
return
res.get()
@ -58,11 +58,11 @@ proc serveSyncCommitteeMessage*(service: SyncCommitteeServiceRef,
try:
await vc.submitPoolSyncCommitteeSignature(message, ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish sync committee message",
message = shortLog(message),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
warn "Unable to publish sync committee message",
message = shortLog(message),
validator = shortLog(validator),
validator_index = vindex,
reason = exc.getFailureReason()
return false
except CancelledError:
debug "Publish sync committee message request was interrupted"
@ -154,10 +154,10 @@ proc serveContributionAndProof*(service: SyncCommitteeServiceRef,
let res = await validator.getContributionAndProofSignature(
fork, genesisRoot, proof)
if res.isErr():
error "Unable to sign sync committee contribution using remote signer",
validator = shortLog(validator),
contribution = shortLog(proof.contribution),
error_msg = res.error()
warn "Unable to sign sync committee contribution using remote signer",
validator = shortLog(validator),
contribution = shortLog(proof.contribution),
error_msg = res.error()
return false
res.get()
debug "Sending sync contribution",
@ -173,12 +173,12 @@ proc serveContributionAndProof*(service: SyncCommitteeServiceRef,
await vc.publishContributionAndProofs(@[restSignedProof],
ApiStrategyKind.First)
except ValidatorApiError as exc:
error "Unable to publish sync contribution",
contribution = shortLog(proof.contribution),
validator = shortLog(validator),
validator_index = validatorIdx,
err_msg = exc.msg,
reason = exc.getFailureReason()
warn "Unable to publish sync contribution",
contribution = shortLog(proof.contribution),
validator = shortLog(validator),
validator_index = validatorIdx,
err_msg = exc.msg,
reason = exc.getFailureReason()
false
except CancelledError:
debug "Publish sync contribution request was interrupted"
@ -251,10 +251,10 @@ proc produceAndPublishContributions(service: SyncCommitteeServiceRef,
sigRes = fut.read
validator = validators[idx][0]
subCommitteeIdx = validators[idx][1]
if sigRes.isErr:
error "Unable to create slot signature using remote signer",
validator = shortLog(validator),
error_msg = sigRes.error()
if sigRes.isErr():
warn "Unable to create slot signature using remote signer",
validator = shortLog(validator),
error_msg = sigRes.error()
elif validator.index.isSome and
is_sync_committee_aggregator(sigRes.get):
res.add ContributionItem(
@ -281,9 +281,9 @@ proc produceAndPublishContributions(service: SyncCommitteeServiceRef,
try:
await contributionsFuts[item.subcommitteeIdx]
except ValidatorApiError as exc:
error "Unable to get sync message contribution data", slot = slot,
beaconBlockRoot = shortLog(beaconBlockRoot),
reason = exc.getFailureReason()
warn "Unable to get sync message contribution data", slot = slot,
beaconBlockRoot = shortLog(beaconBlockRoot),
reason = exc.getFailureReason()
return
except CancelledError:
debug "Request for sync message contribution was interrupted"
@ -365,8 +365,8 @@ proc publishSyncMessagesAndContributions(service: SyncCommitteeServiceRef,
return
res.data.root
except ValidatorApiError as exc:
error "Unable to retrieve head block's root to sign", reason = exc.msg,
reason = exc.getFailureReason()
warn "Unable to retrieve head block's root to sign", reason = exc.msg,
reason = exc.getFailureReason()
return
except CancelledError:
debug "Block root request was interrupted"
@ -381,8 +381,8 @@ proc publishSyncMessagesAndContributions(service: SyncCommitteeServiceRef,
beaconBlockRoot,
duties)
except ValidatorApiError as exc:
error "Unable to proceed sync committee messages", slot = slot,
duties_count = len(duties), reason = exc.getFailureReason()
warn "Unable to proceed sync committee messages", slot = slot,
duties_count = len(duties), reason = exc.getFailureReason()
return
except CancelledError:
debug "Sync committee producing process was interrupted"