diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index 131152bf9b..f19826a47f 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -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 diff --git a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim index 2f9612a419..6004b32a6d 100644 --- a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim +++ b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim @@ -114,6 +114,7 @@ type DataEnclosedObject | DataMetaEnclosedObject | DataRootEnclosedObject | + DataOptimisticObject | DataVersionEnclosedObject | GetBlockV2Response | GetDistributedKeystoresResponse | diff --git a/beacon_chain/spec/eth2_apis/rest_beacon_calls.nim b/beacon_chain/spec/eth2_apis/rest_beacon_calls.nim index 444268becf..371deecb9a 100644 --- a/beacon_chain/spec/eth2_apis/rest_beacon_calls.nim +++ b/beacon_chain/spec/eth2_apis/rest_beacon_calls.nim @@ -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", diff --git a/beacon_chain/spec/eth2_apis/rest_config_calls.nim b/beacon_chain/spec/eth2_apis/rest_config_calls.nim index 1551d4a01f..2368e5d245 100644 --- a/beacon_chain/spec/eth2_apis/rest_config_calls.nim +++ b/beacon_chain/spec/eth2_apis/rest_config_calls.nim @@ -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 diff --git a/beacon_chain/spec/eth2_apis/rest_types.nim b/beacon_chain/spec/eth2_apis/rest_types.nim index 4290589404..e6a4af8ce9 100644 --- a/beacon_chain/spec/eth2_apis/rest_types.nim +++ b/beacon_chain/spec/eth2_apis/rest_types.nim @@ -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] diff --git a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim index a9c35d5bf0..6b3657b8e9 100644 --- a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim +++ b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim @@ -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 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] {. +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 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.} +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 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] {. +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 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] {. +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 diff --git a/beacon_chain/validator_client/api.nim b/beacon_chain/validator_client/api.nim index 8d29f1618f..01a7b9f7bd 100644 --- a/beacon_chain/validator_client/api.nim +++ b/beacon_chain/validator_client/api.nim @@ -19,6 +19,7 @@ const ResponseUnexpectedError = "Received unexpected error response" ResponseNotFoundError = "Received resource missing error response" ResponseNoSyncError = "Received nosync error response" + ResponseDecodeError = "Received response could not be decoded" type ApiResponse*[T] = Result[T, string] @@ -41,8 +42,6 @@ const RestBeaconNodeStatus.NotSynced, RestBeaconNodeStatus.OptSynced, RestBeaconNodeStatus.Synced} - NotSyncedStatus = {RestBeaconNodeStatus.NotSynced, - RestBeaconNodeStatus.OptSynced} proc `$`*(strategy: ApiStrategyKind): string = case strategy @@ -57,9 +56,9 @@ proc lazyWaiter(node: BeaconNodeServerRef, request: FutureBase) {.async.} = try: await allFutures(request) if request.failed(): - node.status = RestBeaconNodeStatus.Offline + node.updateStatus(RestBeaconNodeStatus.Offline) except CancelledError as exc: - node.status = RestBeaconNodeStatus.Offline + node.updateStatus(RestBeaconNodeStatus.Offline) await cancelAndWait(request) proc lazyWait(nodes: seq[BeaconNodeServerRef], requests: seq[FutureBase], @@ -88,11 +87,12 @@ proc lazyWait(nodes: seq[BeaconNodeServerRef], requests: seq[FutureBase], template firstSuccessParallel*( vc: ValidatorClientRef, responseType: typedesc, + handlerType: typedesc, timeout: Duration, statuses: set[RestBeaconNodeStatus], roles: set[BeaconNodeRole], body1, body2: untyped - ): ApiResponse[responseType] = + ): ApiResponse[handlerType] = var it {.inject.}: RestClientRef iterations = 0 @@ -103,7 +103,7 @@ template firstSuccessParallel*( else: nil - var retRes: ApiResponse[responseType] + var retRes: ApiResponse[handlerType] while true: var resultReady = false let onlineNodes = @@ -128,7 +128,7 @@ template firstSuccessParallel*( default if len(onlineNodes) == 0: - retRes = ApiResponse[responseType].err("Operation timeout exceeded") + retRes = ApiResponse[handlerType].err("No online beacon node(s)") resultReady = true else: var (pendingRequests, pendingNodes) = @@ -148,7 +148,7 @@ template firstSuccessParallel*( if len(pendingRequests) == 0: if not(isNil(timerFut)) and not(timerFut.finished()): await timerFut.cancelAndWait() - retRes = ApiResponse[responseType].err( + retRes = ApiResponse[handlerType].err( "Beacon node(s) unable to satisfy request") resultReady = true else: @@ -182,7 +182,7 @@ template firstSuccessParallel*( else: ApiResponse[responseType].ok( Future[responseType](requestFut).read()) - handlerStatus = + handlerResponse = try: body2 except CancelledError as exc: @@ -190,8 +190,8 @@ template firstSuccessParallel*( except CatchableError: raiseAssert("Response handler must not raise exceptions") - if apiResponse.isOk() and handlerStatus: - retRes = apiResponse + if apiResponse.isOk() and handlerResponse.isOk(): + retRes = handlerResponse resultReady = true asyncSpawn lazyWait(pendingNodes, pendingRequests, timerFut) break @@ -201,10 +201,10 @@ template firstSuccessParallel*( pendingCancel.add(raceFut.cancelAndWait()) for index, future in pendingRequests.pairs(): if not(future.finished()): - pendingNodes[index].status = RestBeaconNodeStatus.Offline + pendingNodes[index].updateStatus(RestBeaconNodeStatus.Offline) pendingCancel.add(future.cancelAndWait()) await allFutures(pendingCancel) - retRes = ApiResponse[responseType].err( + retRes = ApiResponse[handlerType].err( "Beacon nodes unable to satisfy request in time") resultReady = true except CancelledError as exc: @@ -215,7 +215,7 @@ template firstSuccessParallel*( pendingCancel.add(timerFut.cancelAndWait()) for index, future in pendingRequests.pairs(): if not(future.finished()): - pendingNodes[index].status = RestBeaconNodeStatus.Offline + pendingNodes[index].updateStatus(RestBeaconNodeStatus.Offline) pendingCancel.add(future.cancelAndWait()) await allFutures(pendingCancel) raise exc @@ -224,7 +224,7 @@ template firstSuccessParallel*( # raise any exceptions. error "Unexpected exception while processing request", err_name = $exc.name, err_msg = $exc.msg - retRes = ApiResponse[responseType].err("Unexpected error") + retRes = ApiResponse[handlerType].err("Unexpected error") resultReady = true if resultReady: break @@ -267,7 +267,7 @@ template bestSuccess*( default if len(onlineNodes) == 0: - ApiResponse[responseType].err("No beacon nodes available") + ApiResponse[responseType].err("No online beacon node(s)") else: let (pendingRequests, pendingNodes) = @@ -323,7 +323,7 @@ template bestSuccess*( debug "One of operation requests has been failed", node = beaconNode, err_name = $exc.name, err_msg = $exc.msg - beaconNode.status = RestBeaconNodeStatus.Offline + beaconNode.status.updateStatus(RestBeaconNodeStatus.Offline) elif future.cancelled(): debug "One of operation requests has been interrupted", node = beaconNode @@ -486,7 +486,7 @@ template onceToAll*( template firstSuccessSequential*( vc: ValidatorClientRef, - respType: typedesc, + responseType: typedesc, timeout: Duration, statuses: set[RestBeaconNodeStatus], roles: set[BeaconNodeRole], @@ -582,19 +582,19 @@ template firstSuccessSequential*( if bodyFut.finished(): if bodyFut.failed() or bodyFut.cancelled(): let exc = bodyFut.readError() - ApiResponse[respType].err("[" & $exc.name & "] " & $exc.msg) + ApiResponse[responseType].err("[" & $exc.name & "] " & $exc.msg) else: - ApiResponse[respType].ok(bodyFut.read()) + ApiResponse[responseType].ok(bodyFut.read()) else: case resOp of ApiOperation.Interrupt: - ApiResponse[respType].err("Operation was interrupted") + ApiResponse[responseType].err("Operation was interrupted") of ApiOperation.Timeout: - ApiResponse[respType].err("Operation timeout exceeded") + ApiResponse[responseType].err("Operation timeout exceeded") of ApiOperation.Success, ApiOperation.Failure: # This should not be happened, because all Futures should be # finished, and `Failure` processed when Future is finished. - ApiResponse[respType].err("Unexpected error") + ApiResponse[responseType].err("Unexpected error") handlerStatus = try: @@ -621,7 +621,7 @@ proc getIndexedErrorMessage(response: RestPlainResponse): string = let failures = errorObj.failures.mapIt($it.index & ": " & it.message) errorObj.message & ": [" & failures.join(", ") & "]" else: - "Unable to decode error response: [" & $res.error() & "]" + "Unable to decode error response: [" & $res.error & "]" proc getErrorMessage(response: RestPlainResponse): string = let res = decodeBytes(RestErrorMessage, response.data, @@ -633,7 +633,7 @@ proc getErrorMessage(response: RestPlainResponse): string = else: errorObj.message else: - "Unable to decode error response: [" & $res.error() & "]" + "Unable to decode error response: [" & $res.error & "]" proc getProposerDuties*( vc: ValidatorClientRef, @@ -649,92 +649,110 @@ proc getProposerDuties*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: - let res = vc.firstSuccessParallel(RestResponse[GetProposerDutiesResponse], + let res = vc.firstSuccessParallel(RestPlainResponse, + GetProposerDutiesResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getProposerDuties(it, epoch)): + getProposerDutiesPlain(it, epoch)): if apiResponse.isErr(): - trace ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetProposerDutiesResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetProposerDutiesResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetProposerDutiesResponse].err($res.error) + else: + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + ApiResponse[GetProposerDutiesResponse].ok(data) of 400: - debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + debug ResponseInvalidError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetProposerDutiesResponse].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetProposerDutiesResponse].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[GetProposerDutiesResponse].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetProposerDutiesResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetProposerDutiesResponse], + vc.firstSuccessSequential(RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getProposerDuties(it, epoch)): + getProposerDutiesPlain(it, epoch)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(GetProposerDutiesResponse, response.data, + response.contentType) + if res.isOk(): + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + return data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -755,92 +773,107 @@ proc getAttesterDuties*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: - let res = vc.firstSuccessParallel(RestResponse[GetAttesterDutiesResponse], + let res = vc.firstSuccessParallel(RestPlainResponse, + GetAttesterDutiesResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getAttesterDuties(it, epoch, validators)): + getAttesterDutiesPlain(it, epoch, + validators)): if apiResponse.isErr(): - trace ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetAttesterDutiesResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetAttesterDutiesResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetAttesterDutiesResponse].err($res.error) + else: + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + ApiResponse[GetAttesterDutiesResponse].ok(data) of 400: - debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + debug ResponseInvalidError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetAttesterDutiesResponse].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetAttesterDutiesResponse].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[GetAttesterDutiesResponse].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetAttesterDutiesResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetAttesterDutiesResponse], + vc.firstSuccessSequential(RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getAttesterDuties(it, epoch, validators)): + getAttesterDutiesPlain(it, epoch, validators)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(GetAttesterDutiesResponse, response.data, + response.contentType) + if res.isOk(): return res.get() + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -862,92 +895,112 @@ proc getSyncCommitteeDuties*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[GetSyncCommitteeDutiesResponse], + RestPlainResponse, + GetSyncCommitteeDutiesResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getSyncCommitteeDuties(it, epoch, validators)): + getSyncCommitteeDutiesPlain(it, epoch, validators)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetSyncCommitteeDutiesResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetSyncCommitteeDutiesResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetSyncCommitteeDutiesResponse].err($res.error) + else: + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + ApiResponse[GetSyncCommitteeDutiesResponse].ok(data) of 400: - debug ResponseInternalError, response_code = response.status, + debug ResponseInvalidError, response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetSyncCommitteeDutiesResponse].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetSyncCommitteeDutiesResponse].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[GetSyncCommitteeDutiesResponse].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetSyncCommitteeDutiesResponse].err( + ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetSyncCommitteeDutiesResponse], - SlotDuration, - ViableNodeStatus, - {BeaconNodeRole.Duties}, - getSyncCommitteeDuties(it, epoch, validators)): + vc.firstSuccessSequential( + RestPlainResponse, + SlotDuration, + ViableNodeStatus, + {BeaconNodeRole.Duties}, + getSyncCommitteeDutiesPlain(it, epoch, validators)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(GetSyncCommitteeDutiesResponse, response.data, + response.contentType) + if res.isOk(): + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + return data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -966,66 +1019,81 @@ proc getForkSchedule*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: - let res = vc.firstSuccessParallel(RestResponse[GetForkScheduleResponse], + let res = vc.firstSuccessParallel(RestPlainResponse, + GetForkScheduleResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getForkSchedule(it)): + getForkSchedulePlain(it)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetForkScheduleResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetForkScheduleResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetForkScheduleResponse].err($res.error) + else: + ApiResponse[GetForkScheduleResponse].ok(res.get()) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetForkScheduleResponse].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetForkScheduleResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data.data + return res.get().data of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetForkScheduleResponse], + vc.firstSuccessSequential(RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getForkSchedule(it)): + getForkSchedulePlain(it)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data.data + let res = decodeBytes(GetForkScheduleResponse, response.data, + response.contentType) + if res.isOk(): return res.get().data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 500: debug ResponseInternalError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + response_code = response.status, endpoint = node, + reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + response_code = response.status, endpoint = node, + reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1034,7 +1102,7 @@ proc getForkSchedule*( proc getHeadBlockRoot*( vc: ValidatorClientRef, strategy: ApiStrategyKind - ): Future[DataRestRoot] {.async.} = + ): Future[DataOptimisticObject[RestRoot]] {.async.} = logScope: request = "getHeadBlockRoot" strategy = $strategy @@ -1046,90 +1114,110 @@ proc getHeadBlockRoot*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: - let res = vc.firstSuccessParallel(RestResponse[GetBlockRootResponse], + let res = vc.firstSuccessParallel(RestPlainResponse, + GetBlockRootResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteeData}, - getBlockRoot(it, blockIdent)): + getBlockRootPlain(it, blockIdent)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetBlockRootResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetBlockRootResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetBlockRootResponse].err($res.error) + else: + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + ApiResponse[GetBlockRootResponse].ok(data) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetBlockRootResponse].err(ResponseInvalidError) of 404: debug ResponseNotFoundError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.NotFound)) - false + ApiResponse[GetBlockRootResponse].err(ResponseNotFoundError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetBlockRootResponse].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetBlockRootResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetBlockRootResponse], + vc.firstSuccessSequential(RestPlainResponse, #RestResponse[GetBlockRootResponse], SlotDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteeData}, - getBlockRoot(it, blockIdent)): + getBlockRootPlain(it, blockIdent)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(GetBlockRootResponse, response.data, + response.contentType) + if res.isOk(): + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + return data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 404: debug ResponseNotFoundError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.NotFound)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1151,90 +1239,111 @@ proc getValidators*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: - let res = vc.firstSuccessParallel(RestResponse[GetStateValidatorsResponse], - SlotDuration, - ViableNodeStatus, - {BeaconNodeRole.Duties}, - getStateValidators(it, stateIdent, id)): + let res = vc.firstSuccessParallel( + RestPlainResponse, + GetStateValidatorsResponse, + SlotDuration, + ViableNodeStatus, + {BeaconNodeRole.Duties}, + getStateValidatorsPlain(it, stateIdent, id)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetStateValidatorsResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetStateValidatorsResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetStateValidatorsResponse].err($res.error) + else: + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + ApiResponse[GetStateValidatorsResponse].ok(data) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetStateValidatorsResponse].err(ResponseInvalidError) of 404: debug ResponseNotFoundError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.NotFound)) - false + ApiResponse[GetStateValidatorsResponse].err(ResponseNotFoundError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetStateValidatorsResponse].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetStateValidatorsResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data.data + return res.get().data of ApiStrategyKind.Priority: - vc.firstSuccessSequential(RestResponse[GetStateValidatorsResponse], + vc.firstSuccessSequential(RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.Duties}, - getStateValidators(it, stateIdent, id)): + getStateValidatorsPlain(it, stateIdent, id)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data.data + let res = decodeBytes(GetStateValidatorsResponse, response.data, + response.contentType) + if res.isOk(): + let data = res.get() + if data.execution_optimistic.get(false): + node.updateStatus(RestBeaconNodeStatus.OptSynced) + return data.data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: - debug ResponseInvalidError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + debug ResponseInvalidError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 404: - debug ResponseNotFoundError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + debug ResponseNotFoundError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.NotFound)) false of 500: - debug ResponseInternalError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + debug ResponseInternalError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: - debug ResponseUnexpectedError, - response_code = response.status, endpoint = node - node.status = RestBeaconNodeStatus.Offline + debug ResponseUnexpectedError, response_code = response.status, + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1256,94 +1365,107 @@ proc produceAttestationData*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[ProduceAttestationDataResponse], + RestPlainResponse, + ProduceAttestationDataResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.AttestationData}, - produceAttestationData(it, slot, committee_index)): + produceAttestationDataPlain(it, slot, committee_index)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[ProduceAttestationDataResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(ProduceAttestationDataResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[ProduceAttestationDataResponse].err($res.error) + else: + ApiResponse[ProduceAttestationDataResponse].ok(res.get()) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[ProduceAttestationDataResponse].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[ProduceAttestationDataResponse].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[ProduceAttestationDataResponse].err( + ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[ProduceAttestationDataResponse].err( + ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data.data + return res.get().data of ApiStrategyKind.Priority: vc.firstSuccessSequential( - RestResponse[ProduceAttestationDataResponse], + RestPlainResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.AttestationData}, - produceAttestationData(it, slot, committee_index)): + produceAttestationDataPlain(it, slot, committee_index)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace ResponseSuccess, endpoint = node - return response.data.data + let res = decodeBytes(ProduceAttestationDataResponse, response.data, + response.contentType) + if res.isOk(): return res.get().data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1366,46 +1488,43 @@ proc submitPoolAttestations*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel(RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.AttestationPublish}, submitPoolAttestations(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace NoErrorMessage, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential(RestPlainResponse, @@ -1414,35 +1533,31 @@ proc submitPoolAttestations*( {BeaconNodeRole.AttestationPublish}, submitPoolAttestations(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace NoErrorMessage, endpoint = node return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1473,46 +1588,43 @@ proc submitPoolSyncCommitteeSignature*( of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteePublish}, submitPoolSyncCommitteeSignatures(it, @[restData])): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status of 200: - trace NoErrorMessage, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential( @@ -1522,35 +1634,31 @@ proc submitPoolSyncCommitteeSignature*( {BeaconNodeRole.SyncCommitteePublish}, submitPoolSyncCommitteeSignatures(it, @[restData])): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status of 200: - trace NoErrorMessage, endpoint = node return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getIndexedErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getIndexedErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1572,79 +1680,95 @@ proc getAggregatedAttestation*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[GetAggregatedAttestationResponse], + RestPlainResponse, + GetAggregatedAttestationResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.AggregatedData}, - getAggregatedAttestation(it, root, slot)): + getAggregatedAttestationPlain(it, root, slot)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[GetAggregatedAttestationResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(GetAggregatedAttestationResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[GetAggregatedAttestationResponse].err($res.error) + else: + ApiResponse[GetAggregatedAttestationResponse].ok(res.get()) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[GetAggregatedAttestationResponse].err( + ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[GetAggregatedAttestationResponse].err( + ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[GetAggregatedAttestationResponse].err( + ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data.data + return res.get().data of ApiStrategyKind.Priority: vc.firstSuccessSequential( - RestResponse[GetAggregatedAttestationResponse], + RestPlainResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.AggregatedData}, - getAggregatedAttestation(it, root, slot)): + getAggregatedAttestationPlain(it, root, slot)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - return response.data.data + let res = decodeBytes(GetAggregatedAttestationResponse, response.data, + response.contentType) + if res.isOk(): return res.get().data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1667,79 +1791,97 @@ proc produceSyncCommitteeContribution*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[ProduceSyncCommitteeContributionResponse], + RestPlainResponse, + ProduceSyncCommitteeContributionResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteeData}, - produceSyncCommitteeContribution(it, slot, subcommitteeIndex, root)): + produceSyncCommitteeContributionPlain(it, slot, subcommitteeIndex, root)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[ProduceSyncCommitteeContributionResponse].err( + apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(ProduceSyncCommitteeContributionResponse, + response.data, response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[ProduceSyncCommitteeContributionResponse].err( + $res.error) + else: + ApiResponse[ProduceSyncCommitteeContributionResponse].ok(res.get()) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[ProduceSyncCommitteeContributionResponse].err( + ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[ProduceSyncCommitteeContributionResponse].err( + ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[ProduceSyncCommitteeContributionResponse].err( + ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data.data + return res.get().data of ApiStrategyKind.Priority: vc.firstSuccessSequential( - RestResponse[ProduceSyncCommitteeContributionResponse], + RestPlainResponse, OneThirdDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteeData}, - produceSyncCommitteeContribution(it, slot, subcommitteeIndex, root)): + produceSyncCommitteeContributionPlain(it, slot, subcommitteeIndex, root)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - return response.data.data + let res = decodeBytes(ProduceSyncCommitteeContributionResponse, + response.data, response.contentType) + if res.isOk(): return res.get().data + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1762,46 +1904,43 @@ proc publishAggregateAndProofs*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel(RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.AggregatedPublish}, publishAggregateAndProofs(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace NoErrorMessage, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential(RestPlainResponse, @@ -1810,35 +1949,31 @@ proc publishAggregateAndProofs*( {BeaconNodeRole.AggregatedPublish}, publishAggregateAndProofs(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace NoErrorMessage, endpoint = node return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1861,46 +1996,43 @@ proc publishContributionAndProofs*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel(RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.SyncCommitteePublish}, publishContributionAndProofs(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace NoErrorMessage, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential(RestPlainResponse, @@ -1909,8 +2041,8 @@ proc publishContributionAndProofs*( {BeaconNodeRole.SyncCommitteePublish}, publishContributionAndProofs(it, data)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: @@ -1921,23 +2053,20 @@ proc publishContributionAndProofs*( return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -1960,93 +2089,104 @@ proc produceBlockV2*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[ProduceBlockResponseV2], + RestPlainResponse, + ProduceBlockResponseV2, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalData}, - produceBlockV2(it, slot, randao_reveal, graffiti)): + produceBlockV2Plain(it, slot, randao_reveal, graffiti)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[ProduceBlockResponseV2].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(ProduceBlockResponseV2, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[ProduceBlockResponseV2].err($res.error) + else: + ApiResponse[ProduceBlockResponseV2].ok(res.get()) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[ProduceBlockResponseV2].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[ProduceBlockResponseV2].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[ProduceBlockResponseV2].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[ProduceBlockResponseV2].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential( - RestResponse[ProduceBlockResponseV2], + RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalData}, - produceBlockV2(it, slot, randao_reveal, graffiti)): + produceBlockV2Plain(it, slot, randao_reveal, graffiti)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(ProduceBlockResponseV2, response.data, + response.contentType) + if res.isOk(): return res.get() + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -2071,6 +2211,7 @@ proc publishBlock*( of ApiStrategyKind.First, ApiStrategyKind.Best: let res = block: vc.firstSuccessParallel(RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalPublish}): @@ -2092,52 +2233,46 @@ proc publishBlock*( do: if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace BlockPublished, endpoint = node - true + ApiResponse[bool].ok(true) of 202: debug BlockBroadcasted, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[bool].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential(RestPlainResponse, @@ -2161,46 +2296,40 @@ proc publishBlock*( f do: if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace BlockPublished, endpoint = node return true of 202: debug BlockBroadcasted, endpoint = node return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -2223,93 +2352,104 @@ proc produceBlindedBlock*( case strategy of ApiStrategyKind.First, ApiStrategyKind.Best: let res = vc.firstSuccessParallel( - RestResponse[ProduceBlindedBlockResponse], + RestPlainResponse, + ProduceBlindedBlockResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalData}, - produceBlindedBlock(it, slot, randao_reveal, graffiti)): + produceBlindedBlockPlain(it, slot, randao_reveal, graffiti)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[ProduceBlindedBlockResponse].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - true + let res = decodeBytes(ProduceBlindedBlockResponse, response.data, + response.contentType) + if res.isErr(): + node.updateStatus(RestBeaconNodeStatus.Unexpected) + ApiResponse[ProduceBlindedBlockResponse].err($res.error) + else: + ApiResponse[ProduceBlindedBlockResponse].ok(res.get()) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[ProduceBlindedBlockResponse].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[ProduceBlindedBlockResponse].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[ProduceBlindedBlockResponse].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[ProduceBlindedBlockResponse].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return res.get().data + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential( - RestResponse[ProduceBlindedBlockResponse], + RestPlainResponse, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalData}, - produceBlindedBlock(it, slot, randao_reveal, graffiti)): + produceBlindedBlockPlain(it, slot, randao_reveal, graffiti)): if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace ResponseSuccess, endpoint = node - return response.data + let res = decodeBytes(ProduceBlindedBlockResponse, response.data, + response.contentType) + if res.isOk(): return res.get() + + debug ResponseDecodeError, response_code = response.status, + endpoint = node, reason = res.error + node.updateStatus(RestBeaconNodeStatus.Unexpected) + failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) + false of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -2334,6 +2474,7 @@ proc publishBlindedBlock*( of ApiStrategyKind.First, ApiStrategyKind.Best: let res = block: vc.firstSuccessParallel(RestPlainResponse, + bool, SlotDuration, ViableNodeStatus, {BeaconNodeRole.BlockProposalPublish}): @@ -2354,52 +2495,46 @@ proc publishBlindedBlock*( f do: if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) - false + ApiResponse[bool].err(apiResponse.error) else: let response = apiResponse.get() case response.status: of 200: - trace BlockPublished, endpoint = node - true + ApiResponse[bool].ok(true) of 202: debug BlockBroadcasted, endpoint = node - true + ApiResponse[bool].ok(true) of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) - false + ApiResponse[bool].err(ResponseInvalidError) of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) - false + ApiResponse[bool].err(ResponseInternalError) of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) - false + ApiResponse[bool].err(ResponseNoSyncError) else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) - false + ApiResponse[bool].err(ResponseUnexpectedError) if res.isErr(): raise (ref ValidatorApiError)(msg: res.error, data: failures) - return true + return res.get() of ApiStrategyKind.Priority: vc.firstSuccessSequential(RestPlainResponse, @@ -2423,46 +2558,40 @@ proc publishBlindedBlock*( f do: if apiResponse.isErr(): - debug ErrorMessage, endpoint = node, error = apiResponse.error() - node.status = RestBeaconNodeStatus.Offline + debug ErrorMessage, endpoint = node, error = apiResponse.error + node.updateStatus(RestBeaconNodeStatus.Offline) failures.add(ApiNodeFailure.init(node, ApiFailure.Communication)) false else: let response = apiResponse.get() case response.status: of 200: - trace BlockPublished, endpoint = node return true of 202: debug BlockBroadcasted, endpoint = node return true of 400: debug ResponseInvalidError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Incompatible + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Incompatible) failures.add(ApiNodeFailure.init(node, ApiFailure.Invalid)) false of 500: debug ResponseInternalError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.InternalError) failures.add(ApiNodeFailure.init(node, ApiFailure.Internal)) false of 503: debug ResponseNoSyncError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - if node.status notin NotSyncedStatus: - node.status = RestBeaconNodeStatus.NotSynced + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.NotSynced) failures.add(ApiNodeFailure.init(node, ApiFailure.NotSynced)) false else: debug ResponseUnexpectedError, response_code = response.status, - endpoint = node, - response_error = response.getErrorMessage() - node.status = RestBeaconNodeStatus.Offline + endpoint = node, reason = response.getErrorMessage() + node.updateStatus(RestBeaconNodeStatus.Unexpected) failures.add(ApiNodeFailure.init(node, ApiFailure.Unexpected)) false @@ -2501,7 +2630,7 @@ proc prepareBeaconCommitteeSubnet*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to subscribe to beacon committee subnets", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() if response.status == 200: @@ -2509,7 +2638,7 @@ proc prepareBeaconCommitteeSubnet*( else: debug "Subscription to beacon commitee subnets failed", status = response.status, endpoint = apiResponse.node, - message = response.getErrorMessage() + reason = response.getErrorMessage() return count proc prepareSyncCommitteeSubnets*( @@ -2544,7 +2673,7 @@ proc prepareSyncCommitteeSubnets*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to prepare sync committee subnets", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() if response.status == 200: @@ -2581,7 +2710,7 @@ proc getValidatorsActivity*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to retrieve validators activity data", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() @@ -2623,29 +2752,31 @@ proc getValidatorsActivity*( list else: debug "Received invalid/incomplete response", - endpoint = apiResponse.node, error_message = res.error() - apiResponse.node.status = RestBeaconNodeStatus.Incompatible + endpoint = apiResponse.node, error_message = res.error + apiResponse.node.updateStatus( + RestBeaconNodeStatus.Unexpected) default of 400: debug "Server reports invalid request", response_code = response.status, endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Incompatible + reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.Incompatible) default of 500: debug "Server reports internal error", response_code = response.status, endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Offline + reason = response.getErrorMessage() + apiResponse.node.updateStatus( + RestBeaconNodeStatus.InternalError) default else: debug "Server reports unexpected error code", response_code = response.status, endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Offline + reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.Unexpected) default if len(activity) > 0: @@ -2691,15 +2822,14 @@ proc prepareBeaconProposer*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to perform beacon proposer preparation request", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() if response.status == 200: inc(count) else: debug "Beacon proposer preparation failed", status = response.status, - endpoint = apiResponse.node, - message = response.getErrorMessage() + endpoint = apiResponse.node, reason = response.getErrorMessage() return count proc registerValidator*( @@ -2734,7 +2864,7 @@ proc registerValidator*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to register validator with beacon node", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() if response.status == 200: @@ -2742,7 +2872,7 @@ proc registerValidator*( else: debug "Unable to register validators with beacon node", status = response.status, endpoint = apiResponse.node, - message = response.getErrorMessage() + reason = response.getErrorMessage() return count proc getValidatorsLiveness*( @@ -2772,7 +2902,7 @@ proc getValidatorsLiveness*( for apiResponse in resp.data: if apiResponse.data.isErr(): debug "Unable to retrieve validators liveness data", - endpoint = apiResponse.node, error = apiResponse.data.error() + endpoint = apiResponse.node, error = apiResponse.data.error else: let response = apiResponse.data.get() case response.status @@ -2804,37 +2934,32 @@ proc getValidatorsLiveness*( updated_count = updated else: debug "Received invalid/incomplete response", - endpoint = apiResponse.node, error_message = res.error() - apiResponse.node.status = RestBeaconNodeStatus.Incompatible + endpoint = apiResponse.node, error_message = res.error + apiResponse.node.updateStatus(RestBeaconNodeStatus.Unexpected) continue of 400: debug "Server reports invalid request", response_code = response.status, - endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Incompatible + endpoint = apiResponse.node, reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.Incompatible) continue of 500: debug "Server reports internal error", response_code = response.status, - endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Offline + endpoint = apiResponse.node, reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.InternalError) continue of 503: debug "Server reports that it not in sync", response_code = response.status, - endpoint = apiResponse.node, - response_error = response.getErrorMessage() - if apiResponse.node.status notin NotSyncedStatus: - apiResponse.node.status = RestBeaconNodeStatus.NotSynced + endpoint = apiResponse.node, reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.NotSynced) continue else: debug "Server reports unexpected error code", response_code = response.status, - endpoint = apiResponse.node, - response_error = response.getErrorMessage() - apiResponse.node.status = RestBeaconNodeStatus.Offline + endpoint = apiResponse.node, reason = response.getErrorMessage() + apiResponse.node.updateStatus(RestBeaconNodeStatus.Unexpected) continue var response = diff --git a/beacon_chain/validator_client/attestation_service.nim b/beacon_chain/validator_client/attestation_service.nim index e30a835507..109a457df9 100644 --- a/beacon_chain/validator_client/attestation_service.nim +++ b/beacon_chain/validator_client/attestation_service.nim @@ -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" diff --git a/beacon_chain/validator_client/block_service.nim b/beacon_chain/validator_client/block_service.nim index 4c4a412043..6dd35788ba 100644 --- a/beacon_chain/validator_client/block_service.nim +++ b/beacon_chain/validator_client/block_service.nim @@ -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) diff --git a/beacon_chain/validator_client/common.nim b/beacon_chain/validator_client/common.nim index 7ac1548578..772d4f497b 100644 --- a/beacon_chain/validator_client/common.nim +++ b/beacon_chain/validator_client/common.nim @@ -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: "" + 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: diff --git a/beacon_chain/validator_client/duties_service.nim b/beacon_chain/validator_client/duties_service.nim index 4af84f2870..52c10354bb 100644 --- a/beacon_chain/validator_client/duties_service.nim +++ b/beacon_chain/validator_client/duties_service.nim @@ -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 diff --git a/beacon_chain/validator_client/fallback_service.nim b/beacon_chain/validator_client/fallback_service.nim index 163da10604..30325fa82f 100644 --- a/beacon_chain/validator_client/fallback_service.nim +++ b/beacon_chain/validator_client/fallback_service.nim @@ -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: diff --git a/beacon_chain/validator_client/fork_service.nim b/beacon_chain/validator_client/fork_service.nim index da1649f99e..b465d846c6 100644 --- a/beacon_chain/validator_client/fork_service.nim +++ b/beacon_chain/validator_client/fork_service.nim @@ -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() diff --git a/beacon_chain/validator_client/sync_committee_service.nim b/beacon_chain/validator_client/sync_committee_service.nim index ce7fb254ed..9f07f00116 100644 --- a/beacon_chain/validator_client/sync_committee_service.nim +++ b/beacon_chain/validator_client/sync_committee_service.nim @@ -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"