Merge remote-tracking branch 'origin/release/v1.1.0' into develop
This commit is contained in:
@@ -30,6 +30,7 @@ pub(crate) mod error;
|
||||
mod helpers;
|
||||
|
||||
use crate::epoch_operations::helpers::stake_to_f64;
|
||||
use crate::node_status_api::ONE_DAY;
|
||||
use error::RewardingError;
|
||||
use mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use task::ShutdownListener;
|
||||
@@ -50,9 +51,6 @@ impl From<MixnodeToReward> for ExecuteMsg {
|
||||
}
|
||||
}
|
||||
|
||||
// // Epoch has all the same semantics as interval, but has a lower set duration
|
||||
// type Epoch = Interval;
|
||||
|
||||
pub struct RewardedSetUpdater {
|
||||
nymd_client: Client<SigningNymdClient>,
|
||||
validator_cache: ValidatorCache,
|
||||
@@ -268,8 +266,8 @@ impl RewardedSetUpdater {
|
||||
log::info!("Advanced the epoch and updated the rewarded set... SUCCESS");
|
||||
}
|
||||
|
||||
log::info!("Puring all node statuses from the storage...");
|
||||
let cutoff = (epoch_end - Duration::from_secs(86400)).unix_timestamp();
|
||||
log::info!("Purging old node statuses from the storage...");
|
||||
let cutoff = (epoch_end - 2 * ONE_DAY).unix_timestamp();
|
||||
self.storage.purge_old_statuses(cutoff).await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -42,6 +42,7 @@ use crate::epoch_operations::RewardedSetUpdater;
|
||||
use coconut::{comm::QueryCommunicationChannel, InternalSignRequest};
|
||||
#[cfg(feature = "coconut")]
|
||||
use coconut_interface::{Base58, KeyPair};
|
||||
use logging::setup_logging;
|
||||
|
||||
pub(crate) mod config;
|
||||
pub(crate) mod contract_cache;
|
||||
@@ -248,27 +249,6 @@ async fn wait_for_signal() {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_logging() {
|
||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
||||
log_builder.parse_filters(&s);
|
||||
} else {
|
||||
// default to 'Info'
|
||||
log_builder.filter(None, log::LevelFilter::Info);
|
||||
}
|
||||
|
||||
log_builder
|
||||
.filter_module("hyper", log::LevelFilter::Warn)
|
||||
.filter_module("tokio_reactor", log::LevelFilter::Warn)
|
||||
.filter_module("reqwest", log::LevelFilter::Warn)
|
||||
.filter_module("mio", log::LevelFilter::Warn)
|
||||
.filter_module("want", log::LevelFilter::Warn)
|
||||
.filter_module("sled", log::LevelFilter::Warn)
|
||||
.filter_module("tungstenite", log::LevelFilter::Warn)
|
||||
.filter_module("tokio_tungstenite", log::LevelFilter::Warn)
|
||||
.init();
|
||||
}
|
||||
|
||||
fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
if let Some(id) = matches.value_of(ID) {
|
||||
fs::create_dir_all(Config::default_config_directory(Some(id)))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::contract_cache::{Cache, CacheNotification, ValidatorCache};
|
||||
use mixnet_contract_common::rewarding::helpers::truncate_decimal;
|
||||
use contracts_common::truncate_decimal;
|
||||
use mixnet_contract_common::{MixId, MixNodeDetails, RewardingParams};
|
||||
use rocket::fairing::AdHoc;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -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<MixnodeStatusReport, ErrorResponse> {
|
||||
) -> Result<MixnodeStatusReportResponse, ErrorResponse> {
|
||||
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<MixnodeUptimeHistory, ErrorResponse> {
|
||||
) -> Result<MixnodeUptimeHistoryResponse, ErrorResponse> {
|
||||
storage
|
||||
.get_mixnode_uptime_history(mix_id)
|
||||
.await
|
||||
.map(MixnodeUptimeHistoryResponse::from)
|
||||
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ use crate::storage::models::NodeStatus;
|
||||
use mixnet_contract_common::reward_params::Performance;
|
||||
use mixnet_contract_common::{IdentityKey, MixId};
|
||||
use okapi::openapi3::{Responses, SchemaObject};
|
||||
use rocket::http::{ContentType, Status};
|
||||
use rocket::http::Status;
|
||||
use rocket::response::{self, Responder, Response};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::Request;
|
||||
use rocket_okapi::gen::OpenApiGenerator;
|
||||
use rocket_okapi::response::OpenApiResponderInner;
|
||||
@@ -19,8 +20,11 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::Error;
|
||||
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, RequestError,
|
||||
};
|
||||
|
||||
// todo: put into some error enum
|
||||
#[derive(Debug)]
|
||||
@@ -153,6 +157,19 @@ impl MixnodeStatusReport {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MixnodeStatusReport> 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<GatewayStatusReport> 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<MixnodeUptimeHistory> 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<GatewayUptimeHistory> 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,25 +292,35 @@ pub struct HistoricalUptime {
|
||||
pub(crate) uptime: Uptime,
|
||||
}
|
||||
|
||||
impl From<HistoricalUptime> for HistoricalUptimeResponse {
|
||||
fn from(uptime: HistoricalUptime) -> Self {
|
||||
HistoricalUptimeResponse {
|
||||
date: uptime.date,
|
||||
uptime: uptime.uptime.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ErrorResponse {
|
||||
error_message: String,
|
||||
error_message: RequestError,
|
||||
status: Status,
|
||||
}
|
||||
|
||||
impl ErrorResponse {
|
||||
pub(crate) fn new(error_message: impl Into<String>, status: Status) -> Self {
|
||||
ErrorResponse {
|
||||
error_message: error_message.into(),
|
||||
error_message: RequestError::new(error_message),
|
||||
status,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'o: 'r> Responder<'r, 'o> for ErrorResponse {
|
||||
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
|
||||
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
|
||||
// piggyback on the existing implementation
|
||||
// also prefer json over plain for ease of use in frontend
|
||||
Response::build()
|
||||
.header(ContentType::Plain)
|
||||
.sized_body(self.error_message.len(), Cursor::new(self.error_message))
|
||||
.merge(Json(self.error_message).respond_to(req)?)
|
||||
.status(self.status)
|
||||
.ok()
|
||||
}
|
||||
|
||||
@@ -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<ValidatorApiStorage>,
|
||||
identity: &str,
|
||||
) -> Result<Json<GatewayStatusReport>, ErrorResponse> {
|
||||
) -> Result<Json<GatewayStatusReportResponse>, 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<ValidatorApiStorage>,
|
||||
identity: &str,
|
||||
) -> Result<Json<GatewayUptimeHistory>, ErrorResponse> {
|
||||
) -> Result<Json<GatewayUptimeHistoryResponse>, 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<ValidatorApiStorage>,
|
||||
mix_id: MixId,
|
||||
) -> Result<Json<MixnodeStatusReport>, ErrorResponse> {
|
||||
) -> Result<Json<MixnodeStatusReportResponse>, 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<ValidatorApiStorage>,
|
||||
mix_id: MixId,
|
||||
) -> Result<Json<MixnodeUptimeHistory>, ErrorResponse> {
|
||||
) -> Result<Json<MixnodeUptimeHistoryResponse>, ErrorResponse> {
|
||||
Ok(Json(_mixnode_uptime_history(storage, mix_id).await?))
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ use crate::node_status_api::models::{
|
||||
use crate::node_status_api::ONE_DAY;
|
||||
use crate::storage::ValidatorApiStorage;
|
||||
use log::error;
|
||||
use std::time::Duration;
|
||||
use task::ShutdownListener;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::time::sleep;
|
||||
use time::{OffsetDateTime, PrimitiveDateTime, Time};
|
||||
use tokio::time::{interval, sleep};
|
||||
|
||||
pub(crate) struct HistoricalUptimeUpdater {
|
||||
storage: ValidatorApiStorage,
|
||||
@@ -69,28 +70,51 @@ impl HistoricalUptimeUpdater {
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&self, mut shutdown: ShutdownListener) {
|
||||
// update uptimes at 23:00 UTC each day so that we'd have data from the actual [almost] whole day
|
||||
// and so that we would avoid the edge case of starting validator API at 23:59 and having some
|
||||
// nodes update for different days
|
||||
|
||||
// the unwrap is fine as 23:00:00 is a valid time
|
||||
let update_time = Time::from_hms(23, 0, 0).unwrap();
|
||||
let now = OffsetDateTime::now_utc();
|
||||
// is the current time within 0:00 - 22:59:59 or 23:00 - 23:59:59 ?
|
||||
let update_date = if now.hour() < 23 {
|
||||
now.date()
|
||||
} else {
|
||||
// the unwrap is fine as (**PRESUMABLY**) we're not running this code in the year 9999
|
||||
now.date().next_day().unwrap()
|
||||
};
|
||||
let update_datetime = PrimitiveDateTime::new(update_date, update_time).assume_utc();
|
||||
// the unwrap here is fine as we're certain `update_datetime` is in the future and thus the
|
||||
// resultant Duration is positive
|
||||
let time_left: Duration = (update_datetime - now).try_into().unwrap();
|
||||
|
||||
log::info!(
|
||||
"waiting until {update_datetime} to update the historical uptimes for the first time ({} seconds left)", time_left.as_secs()
|
||||
);
|
||||
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
trace!("UpdateHandler: Received shutdown");
|
||||
}
|
||||
_ = sleep(time_left) => {}
|
||||
}
|
||||
|
||||
let mut interval = interval(ONE_DAY);
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = sleep(ONE_DAY) => {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
trace!("UpdateHandler: Received shutdown");
|
||||
}
|
||||
Err(err) = self.update_uptimes() => {
|
||||
// normally that would have been a warning rather than an error,
|
||||
// however, in this case it implies some underlying issues with our database
|
||||
// that might affect the entire program
|
||||
error!(
|
||||
"We failed to update daily uptimes of active nodes - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
trace!("UpdateHandler: Received shutdown");
|
||||
}
|
||||
_ = interval.tick() => {
|
||||
// we don't want to have another select here; uptime update is relatively speedy
|
||||
// and we don't want to exit while we're in the middle of database update
|
||||
if let Err(err) = self.update_uptimes().await {
|
||||
error!("We failed to update daily uptimes of active nodes - {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user