Feature/validator api client endpoints (#1024)

* Moved mixnode status route to node status api module

* Introduced validator-api endpoint for estimating mixnode's reward

* Stake saturation endpoint

* kebab-cased coconut routes

* Created separate crate for validator API models

* Additional routes in validator API client

* Introduced support for new queries in the wallet

* Typescript type derivation

* Fixed up date in license notice
This commit is contained in:
Jędrzej Stuczyński
2022-01-11 16:37:07 +00:00
committed by GitHub
parent 835d4f46f6
commit e2e06df4e6
27 changed files with 499 additions and 106 deletions
+2 -1
View File
@@ -39,7 +39,7 @@ time = { version = "0.3", features = ["serde-human-readable", "parsing"]}
anyhow = "1"
getset = "0.1.1"
rocket_sync_db_pools = {version = "0.1.0-rc.1", default-features = false}
rocket_sync_db_pools = { version = "0.1.0-rc.1", default-features = false }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]}
@@ -50,6 +50,7 @@ gateway-client = { path="../common/client-libs/gateway-client" }
mixnet-contract = { path="../common/mixnet-contract" }
nymsphinx = { path="../common/nymsphinx" }
topology = { path="../common/topology" }
validator-api-requests = { path = "validator-api-requests" }
validator-client = { path="../common/client-libs/validator-client", features = ["nymd-client"] }
version-checker = { path="../common/version-checker" }
coconut-interface = { path = "../common/coconut-interface", optional = true }
+1 -15
View File
@@ -20,26 +20,12 @@ use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
use tokio::time;
use validator_api_requests::models::MixnodeStatus;
use validator_client::nymd::hash::SHA256_HASH_SIZE;
use validator_client::nymd::CosmWasmClient;
pub(crate) mod routes;
#[derive(Clone, Copy, Debug, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MixnodeStatus {
Active, // in both the active set and the rewarded set
Standby, // only in the rewarded set
Inactive, // in neither the rewarded set nor the active set, but is bonded
NotFound, // doesn't even exist in the bonded set
}
impl MixnodeStatus {
pub fn is_active(&self) -> bool {
*self == MixnodeStatus::Active
}
}
pub struct ValidatorCacheRefresher<C> {
nymd_client: Client<C>,
cache: ValidatorCache,
+2 -2
View File
@@ -62,7 +62,7 @@ fn blind_sign(request: InternalSignRequest, key_pair: &KeyPair) -> BlindedSignat
.unwrap()
}
#[post("/blind_sign", data = "<blind_sign_request_body>")]
#[post("/blind-sign", data = "<blind_sign_request_body>")]
// Until we have serialization and deserialization traits we'll be using a crutch
pub async fn post_blind_sign(
blind_sign_request_body: Json<BlindSignRequestBody>,
@@ -79,7 +79,7 @@ pub async fn post_blind_sign(
Json(BlindedSignatureResponse::new(blinded_signature))
}
#[get("/verification_key")]
#[get("/verification-key")]
pub async fn get_verification_key(key_pair: &State<KeyPair>) -> Json<VerificationKeyResponse> {
Json(VerificationKeyResponse::new(key_pair.verification_key()))
}
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cache::MixnodeStatus;
use crate::node_status_api::utils::NodeUptimes;
use crate::storage::models::NodeStatus;
use rocket::http::{ContentType, Status};
@@ -272,32 +271,3 @@ impl Display for ValidatorApiStorageError {
}
}
}
#[derive(Serialize)]
pub struct CoreNodeStatus {
pub(crate) identity: String,
pub(crate) count: i32,
}
#[derive(Serialize)]
pub(crate) struct MixnodeStatusResponse {
pub(crate) status: MixnodeStatus,
}
#[derive(Serialize)]
pub(crate) struct RewardEstimationResponse {
pub(crate) estimated_total_node_reward: u128,
pub(crate) estimated_operator_reward: u128,
pub(crate) estimated_delegators_reward: u128,
pub(crate) current_epoch_start: i64,
pub(crate) current_epoch_end: i64,
pub(crate) current_epoch_uptime: Uptime,
pub(crate) as_at: i64,
}
#[derive(Serialize)]
pub(crate) struct StakeSaturationResponse {
pub(crate) saturation: f32,
pub(crate) as_at: i64,
}
+33 -29
View File
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node_status_api::models::{
CoreNodeStatus, ErrorResponse, GatewayStatusReport, GatewayUptimeHistory, MixnodeStatusReport,
MixnodeStatusResponse, MixnodeUptimeHistory, RewardEstimationResponse, StakeSaturationResponse,
ErrorResponse, GatewayStatusReport, GatewayUptimeHistory, MixnodeStatusReport,
MixnodeUptimeHistory,
};
use crate::storage::ValidatorApiStorage;
use crate::{Epoch, ValidatorCache};
@@ -11,85 +11,89 @@ use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use time::OffsetDateTime;
use validator_api_requests::models::{
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
StakeSaturationResponse,
};
#[get("/mixnode/<pubkey>/report")]
#[get("/mixnode/<identity>/report")]
pub(crate) async fn mixnode_report(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
) -> Result<Json<MixnodeStatusReport>, ErrorResponse> {
storage
.construct_mixnode_report(pubkey)
.construct_mixnode_report(identity)
.await
.map(Json)
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[get("/gateway/<pubkey>/report")]
#[get("/gateway/<identity>/report")]
pub(crate) async fn gateway_report(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
) -> Result<Json<GatewayStatusReport>, ErrorResponse> {
storage
.construct_gateway_report(pubkey)
.construct_gateway_report(identity)
.await
.map(Json)
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[get("/mixnode/<pubkey>/history")]
#[get("/mixnode/<identity>/history")]
pub(crate) async fn mixnode_uptime_history(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
) -> Result<Json<MixnodeUptimeHistory>, ErrorResponse> {
storage
.get_mixnode_uptime_history(pubkey)
.get_mixnode_uptime_history(identity)
.await
.map(Json)
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[get("/gateway/<pubkey>/history")]
#[get("/gateway/<identity>/history")]
pub(crate) async fn gateway_uptime_history(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
) -> Result<Json<GatewayUptimeHistory>, ErrorResponse> {
storage
.get_gateway_uptime_history(pubkey)
.get_gateway_uptime_history(identity)
.await
.map(Json)
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[get("/mixnode/<pubkey>/core-status-count?<since>")]
#[get("/mixnode/<identity>/core-status-count?<since>")]
pub(crate) async fn mixnode_core_status_count(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
since: Option<i64>,
) -> Json<CoreNodeStatus> {
) -> Json<CoreNodeStatusResponse> {
let count = storage
.get_core_mixnode_status_count(pubkey, since)
.get_core_mixnode_status_count(identity, since)
.await
.unwrap_or_default();
Json(CoreNodeStatus {
identity: pubkey.to_string(),
Json(CoreNodeStatusResponse {
identity: identity.to_string(),
count,
})
}
#[get("/gateway/<pubkey>/core-status-count?<since>")]
#[get("/gateway/<identity>/core-status-count?<since>")]
pub(crate) async fn gateway_core_status_count(
storage: &State<ValidatorApiStorage>,
pubkey: &str,
identity: &str,
since: Option<i64>,
) -> Json<CoreNodeStatus> {
) -> Json<CoreNodeStatusResponse> {
let count = storage
.get_core_gateway_status_count(pubkey, since)
.get_core_gateway_status_count(identity, since)
.await
.unwrap_or_default();
Json(CoreNodeStatus {
identity: pubkey.to_string(),
Json(CoreNodeStatusResponse {
identity: identity.to_string(),
count,
})
}
@@ -104,7 +108,7 @@ pub(crate) async fn get_mixnode_status(
})
}
#[get("/mixnode/<identity>/reward_estimation")]
#[get("/mixnode/<identity>/reward-estimation")]
pub(crate) async fn get_mixnode_reward_estimation(
cache: &State<ValidatorCache>,
storage: &State<ValidatorApiStorage>,
@@ -136,7 +140,7 @@ pub(crate) async fn get_mixnode_reward_estimation(
estimated_delegators_reward,
current_epoch_start: current_epoch.start_unix_timestamp(),
current_epoch_end: current_epoch.end_unix_timestamp(),
current_epoch_uptime: uptime,
current_epoch_uptime: uptime.u8(),
as_at,
}))
} else {
@@ -147,7 +151,7 @@ pub(crate) async fn get_mixnode_reward_estimation(
}
}
#[get("/mixnode/<identity>/stake_saturation")]
#[get("/mixnode/<identity>/stake-saturation")]
pub(crate) async fn get_mixnode_stake_saturation(
cache: &State<ValidatorCache>,
identity: String,
@@ -0,0 +1,11 @@
[package]
name = "validator-api-requests"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = "1.0"
ts-rs = { version = "5.1", optional = true }
@@ -0,0 +1,4 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod models;
@@ -0,0 +1,53 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[serde(rename_all = "snake_case")]
pub enum MixnodeStatus {
Active, // in both the active set and the rewarded set
Standby, // only in the rewarded set
Inactive, // in neither the rewarded set nor the active set, but is bonded
NotFound, // doesn't even exist in the bonded set
}
impl MixnodeStatus {
pub fn is_active(&self) -> bool {
*self == MixnodeStatus::Active
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
pub struct CoreNodeStatusResponse {
pub identity: String,
pub count: i32,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
pub struct MixnodeStatusResponse {
pub status: MixnodeStatus,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
pub struct RewardEstimationResponse {
pub estimated_total_node_reward: u128,
pub estimated_operator_reward: u128,
pub estimated_delegators_reward: u128,
pub current_epoch_start: i64,
pub current_epoch_end: i64,
pub current_epoch_uptime: u8,
pub as_at: i64,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
pub struct StakeSaturationResponse {
pub saturation: f32,
pub as_at: i64,
}