Merge remote-tracking branch 'origin/release/v1.1.0' into develop

This commit is contained in:
Jon Häggblad
2022-11-07 10:13:33 +01:00
174 changed files with 2787 additions and 951 deletions
+3 -5
View File
@@ -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(())
+1 -21
View File
@@ -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)))
+1 -1
View File
@@ -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;
+7 -4
View File
@@ -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))
}
+67 -7
View File
@@ -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()
}
+11 -10
View File
@@ -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}");
}
}
}
}
}