diff --git a/Cargo.lock b/Cargo.lock index bfe183e51c..c7367f201e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1585,8 +1585,8 @@ version = "1.0.1" dependencies = [ "chrono", "clap 3.2.8", - "dotenv", "contracts-common", + "dotenv", "humantime-serde", "isocountry", "itertools", diff --git a/common/client-libs/validator-client/src/validator_api/mod.rs b/common/client-libs/validator-client/src/validator_api/mod.rs index ee501a19e0..faed34b4dc 100644 --- a/common/client-libs/validator-client/src/validator_api/mod.rs +++ b/common/client-libs/validator-client/src/validator_api/mod.rs @@ -12,9 +12,10 @@ use validator_api_requests::coconut::{ VerifyCredentialBody, VerifyCredentialResponse, }; use validator_api_requests::models::{ - GatewayCoreStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated, - MixnodeCoreStatusResponse, MixnodeStatusResponse, RewardEstimationResponse, - StakeSaturationResponse, UptimeResponse, + GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse, + InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse, + MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, + RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, }; pub mod error; @@ -135,6 +136,74 @@ impl Client { .await } + pub async fn get_mixnode_report( + &self, + mix_id: MixId, + ) -> Result { + self.query_validator_api( + &[ + routes::API_VERSION, + routes::STATUS, + routes::MIXNODE, + &mix_id.to_string(), + routes::REPORT, + ], + NO_PARAMS, + ) + .await + } + + pub async fn get_gateway_report( + &self, + identity: IdentityKeyRef<'_>, + ) -> Result { + self.query_validator_api( + &[ + routes::API_VERSION, + routes::STATUS, + routes::GATEWAY, + identity, + routes::REPORT, + ], + NO_PARAMS, + ) + .await + } + + pub async fn get_mixnode_history( + &self, + mix_id: MixId, + ) -> Result { + self.query_validator_api( + &[ + routes::API_VERSION, + routes::STATUS, + routes::MIXNODE, + &mix_id.to_string(), + routes::HISTORY, + ], + NO_PARAMS, + ) + .await + } + + pub async fn get_gateway_history( + &self, + identity: IdentityKeyRef<'_>, + ) -> Result { + self.query_validator_api( + &[ + routes::API_VERSION, + routes::STATUS, + routes::GATEWAY, + identity, + routes::HISTORY, + ], + NO_PARAMS, + ) + .await + } + pub async fn get_rewarded_mixnodes_detailed( &self, ) -> Result, ValidatorAPIError> { diff --git a/common/client-libs/validator-client/src/validator_api/routes.rs b/common/client-libs/validator-client/src/validator_api/routes.rs index 8f1a125c80..5100f59e05 100644 --- a/common/client-libs/validator-client/src/validator_api/routes.rs +++ b/common/client-libs/validator-client/src/validator_api/routes.rs @@ -28,6 +28,8 @@ pub const CORE_STATUS_COUNT: &str = "core-status-count"; pub const SINCE_ARG: &str = "since"; pub const STATUS: &str = "status"; +pub const REPORT: &str = "report"; +pub const HISTORY: &str = "history"; pub const REWARD_ESTIMATION: &str = "reward-estimation"; pub const AVG_UPTIME: &str = "avg_uptime"; pub const STAKE_SATURATION: &str = "stake-saturation"; diff --git a/validator-api/src/node_status_api/helpers.rs b/validator-api/src/node_status_api/helpers.rs index 6beca7731a..c0c2a544bd 100644 --- a/validator-api/src/node_status_api/helpers.rs +++ b/validator-api/src/node_status_api/helpers.rs @@ -3,7 +3,7 @@ use crate::contract_cache::reward_estimate::compute_reward_estimate; use crate::contract_cache::Cache; -use crate::node_status_api::models::{ErrorResponse, MixnodeStatusReport, MixnodeUptimeHistory}; +use crate::node_status_api::models::ErrorResponse; use crate::storage::ValidatorApiStorage; use crate::{NodeStatusCache, ValidatorCache}; use cosmwasm_std::Decimal; @@ -13,26 +13,29 @@ use rocket::http::Status; use rocket::State; use validator_api_requests::models::{ ComputeRewardEstParam, InclusionProbabilityResponse, MixnodeCoreStatusResponse, - MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, + MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, + RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, }; pub(crate) async fn _mixnode_report( storage: &ValidatorApiStorage, mix_id: MixId, -) -> Result { +) -> Result { storage .construct_mixnode_report(mix_id) .await + .map(MixnodeStatusReportResponse::from) .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound)) } pub(crate) async fn _mixnode_uptime_history( storage: &ValidatorApiStorage, mix_id: MixId, -) -> Result { +) -> Result { storage .get_mixnode_uptime_history(mix_id) .await + .map(MixnodeUptimeHistoryResponse::from) .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound)) } diff --git a/validator-api/src/node_status_api/models.rs b/validator-api/src/node_status_api/models.rs index 6fb54a6f22..b793db5901 100644 --- a/validator-api/src/node_status_api/models.rs +++ b/validator-api/src/node_status_api/models.rs @@ -21,6 +21,10 @@ use std::convert::TryFrom; use std::fmt::{self, Display, Formatter}; use std::io::Cursor; use time::OffsetDateTime; +use validator_api_requests::models::{ + GatewayStatusReportResponse, GatewayUptimeHistoryResponse, HistoricalUptimeResponse, + MixnodeStatusReportResponse, MixnodeUptimeHistoryResponse, +}; // todo: put into some error enum #[derive(Debug)] @@ -153,6 +157,19 @@ impl MixnodeStatusReport { } } +impl From for MixnodeStatusReportResponse { + fn from(status: MixnodeStatusReport) -> Self { + MixnodeStatusReportResponse { + mix_id: status.mix_id, + identity: status.identity, + owner: status.owner, + most_recent: status.most_recent.0, + last_hour: status.last_hour.0, + last_day: status.last_day.0, + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)] pub struct GatewayStatusReport { pub(crate) identity: String, @@ -190,6 +207,18 @@ impl GatewayStatusReport { } } +impl From for GatewayStatusReportResponse { + fn from(status: GatewayStatusReport) -> Self { + GatewayStatusReportResponse { + identity: status.identity, + owner: status.owner, + most_recent: status.most_recent.0, + last_hour: status.last_hour.0, + last_day: status.last_day.0, + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)] pub struct MixnodeUptimeHistory { pub(crate) mix_id: MixId, @@ -215,6 +244,17 @@ impl MixnodeUptimeHistory { } } +impl From for MixnodeUptimeHistoryResponse { + fn from(history: MixnodeUptimeHistory) -> Self { + MixnodeUptimeHistoryResponse { + mix_id: history.mix_id, + identity: history.identity, + owner: history.owner, + history: history.history.into_iter().map(Into::into).collect(), + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)] pub struct GatewayUptimeHistory { pub(crate) identity: String, @@ -233,6 +273,16 @@ impl GatewayUptimeHistory { } } +impl From for GatewayUptimeHistoryResponse { + fn from(history: GatewayUptimeHistory) -> Self { + GatewayUptimeHistoryResponse { + identity: history.identity, + owner: history.owner, + history: history.history.into_iter().map(Into::into).collect(), + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)] pub struct HistoricalUptime { // ISO 8601 date string @@ -242,6 +292,15 @@ pub struct HistoricalUptime { pub(crate) uptime: Uptime, } +impl From for HistoricalUptimeResponse { + fn from(uptime: HistoricalUptime) -> Self { + HistoricalUptimeResponse { + date: uptime.date, + uptime: uptime.uptime.0, + } + } +} + pub(crate) struct ErrorResponse { error_message: String, status: Status, diff --git a/validator-api/src/node_status_api/routes.rs b/validator-api/src/node_status_api/routes.rs index 72a476f841..7665f1bac1 100644 --- a/validator-api/src/node_status_api/routes.rs +++ b/validator-api/src/node_status_api/routes.rs @@ -8,10 +8,7 @@ use crate::node_status_api::helpers::{ _get_mixnode_stake_saturation, _get_mixnode_status, _mixnode_core_status_count, _mixnode_report, _mixnode_uptime_history, }; -use crate::node_status_api::models::{ - ErrorResponse, GatewayStatusReport, GatewayUptimeHistory, MixnodeStatusReport, - MixnodeUptimeHistory, -}; +use crate::node_status_api::models::ErrorResponse; use crate::storage::ValidatorApiStorage; use crate::ValidatorCache; use mixnet_contract_common::MixId; @@ -21,8 +18,10 @@ use rocket::State; use rocket_okapi::openapi; use validator_api_requests::models::{ AllInclusionProbabilitiesResponse, ComputeRewardEstParam, GatewayCoreStatusResponse, - InclusionProbabilityResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse, - RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, + GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse, + MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse, + MixnodeUptimeHistoryResponse, RewardEstimationResponse, StakeSaturationResponse, + UptimeResponse, }; #[openapi(tag = "status")] @@ -30,10 +29,11 @@ use validator_api_requests::models::{ pub(crate) async fn gateway_report( storage: &State, identity: &str, -) -> Result, ErrorResponse> { +) -> Result, ErrorResponse> { storage .construct_gateway_report(identity) .await + .map(GatewayStatusReportResponse::from) .map(Json) .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound)) } @@ -43,10 +43,11 @@ pub(crate) async fn gateway_report( pub(crate) async fn gateway_uptime_history( storage: &State, identity: &str, -) -> Result, ErrorResponse> { +) -> Result, ErrorResponse> { storage .get_gateway_uptime_history(identity) .await + .map(GatewayUptimeHistoryResponse::from) .map(Json) .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound)) } @@ -74,7 +75,7 @@ pub(crate) async fn gateway_core_status_count( pub(crate) async fn mixnode_report( storage: &State, mix_id: MixId, -) -> Result, ErrorResponse> { +) -> Result, ErrorResponse> { Ok(Json(_mixnode_report(storage, mix_id).await?)) } @@ -83,7 +84,7 @@ pub(crate) async fn mixnode_report( pub(crate) async fn mixnode_uptime_history( storage: &State, mix_id: MixId, -) -> Result, ErrorResponse> { +) -> Result, ErrorResponse> { Ok(Json(_mixnode_uptime_history(storage, mix_id).await?)) } diff --git a/validator-api/validator-api-requests/src/models.rs b/validator-api/validator-api-requests/src/models.rs index 398fe65c00..9435749fb0 100644 --- a/validator-api/validator-api-requests/src/models.rs +++ b/validator-api/validator-api-requests/src/models.rs @@ -5,7 +5,9 @@ use cosmwasm_std::{Coin, Decimal}; use mixnet_contract_common::mixnode::MixNodeDetails; use mixnet_contract_common::reward_params::{Performance, RewardingParams}; use mixnet_contract_common::rewarding::RewardEstimate; -use mixnet_contract_common::{Interval, MixId, MixNode, Percent, RewardedSetNodeStatus}; +use mixnet_contract_common::{ + IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{fmt, time::Duration}; @@ -219,3 +221,45 @@ pub struct InclusionProbability { pub in_active: f64, pub in_reserve: f64, } + +type Uptime = u8; + +#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] +pub struct MixnodeStatusReportResponse { + pub mix_id: MixId, + pub identity: IdentityKey, + pub owner: String, + pub most_recent: Uptime, + pub last_hour: Uptime, + pub last_day: Uptime, +} + +#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] +pub struct GatewayStatusReportResponse { + pub identity: String, + pub owner: String, + pub most_recent: Uptime, + pub last_hour: Uptime, + pub last_day: Uptime, +} + +#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] +pub struct HistoricalUptimeResponse { + pub date: String, + pub uptime: Uptime, +} + +#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] +pub struct MixnodeUptimeHistoryResponse { + pub mix_id: MixId, + pub identity: String, + pub owner: String, + pub history: Vec, +} + +#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] +pub struct GatewayUptimeHistoryResponse { + pub identity: String, + pub owner: String, + pub history: Vec, +}