diff --git a/validator-api/src/main.rs b/validator-api/src/main.rs index 842f12f15f..19a1f3b8bd 100644 --- a/validator-api/src/main.rs +++ b/validator-api/src/main.rs @@ -8,10 +8,11 @@ use crate::cache::ValidatorCacheRefresher; use crate::config::Config; use crate::network_monitor::tested_network::good_topology::parse_topology_file; use crate::network_monitor::NetworkMonitorBuilder; +use crate::node_status_api::uptime_updater::HistoricalUptimeUpdater; use crate::nymd_client::Client; use crate::rewarding::epoch::Epoch; use crate::rewarding::Rewarder; -use crate::storage::NodeStatusStorage; +use crate::storage::ValidatorApiStorage; use ::config::NymConfig; use anyhow::Result; use cache::ValidatorCache; @@ -335,7 +336,7 @@ fn setup_network_monitor<'a>( } // get instances of managed states - let node_status_storage = rocket.state::().unwrap().clone(); + let node_status_storage = rocket.state::().unwrap().clone(); let validator_cache = rocket.state::().unwrap().clone(); let v4_topology = parse_topology_file(config.get_v4_good_topology_file()); @@ -367,7 +368,7 @@ fn setup_rewarder( ) -> Option { if config.get_rewarding_enabled() && config.get_network_monitor_enabled() { // get instances of managed states - let node_status_storage = rocket.state::().unwrap().clone(); + let node_status_storage = rocket.state::().unwrap().clone(); let validator_cache = rocket.state::().unwrap().clone(); let first_epoch = Epoch::new( @@ -475,6 +476,12 @@ async fn main() -> Result<()> { // spawn our cacher tokio::spawn(async move { validator_cache_refresher.run().await }); + // setup our daily uptime updater. Note that if network monitor is disabled, then we have + // no data for the updates and hence we don't need to start it up + let storage = rocket.state::().unwrap().clone(); + let uptime_updater = HistoricalUptimeUpdater::new(storage); + tokio::spawn(async move { uptime_updater.run().await }); + if let Some(rewarder) = setup_rewarder(&config, &rocket, &nymd_client) { info!("Periodic rewarding is starting..."); tokio::spawn(async move { rewarder.run().await }); diff --git a/validator-api/src/network_monitor/mod.rs b/validator-api/src/network_monitor/mod.rs index 78820e3c2a..019f16e9d0 100644 --- a/validator-api/src/network_monitor/mod.rs +++ b/validator-api/src/network_monitor/mod.rs @@ -14,7 +14,7 @@ use crate::network_monitor::monitor::sender::PacketSender; use crate::network_monitor::monitor::summary_producer::SummaryProducer; use crate::network_monitor::monitor::Monitor; use crate::network_monitor::tested_network::TestedNetwork; -use crate::storage::NodeStatusStorage; +use crate::storage::ValidatorApiStorage; use crypto::asymmetric::{encryption, identity}; use futures::channel::mpsc; use log::info; @@ -36,7 +36,7 @@ pub(crate) mod tested_network; pub(crate) struct NetworkMonitorBuilder<'a> { config: &'a Config, tested_network: TestedNetwork, - node_status_storage: NodeStatusStorage, + node_status_storage: ValidatorApiStorage, validator_cache: ValidatorCache, } @@ -45,7 +45,7 @@ impl<'a> NetworkMonitorBuilder<'a> { config: &'a Config, v4_topology: NymTopology, v6_topology: NymTopology, - node_status_storage: NodeStatusStorage, + node_status_storage: ValidatorApiStorage, validator_cache: ValidatorCache, ) -> Self { let tested_network = TestedNetwork::new_good(v4_topology, v6_topology); diff --git a/validator-api/src/network_monitor/monitor/mod.rs b/validator-api/src/network_monitor/monitor/mod.rs index 39bbe0dda9..c4246c4100 100644 --- a/validator-api/src/network_monitor/monitor/mod.rs +++ b/validator-api/src/network_monitor/monitor/mod.rs @@ -8,7 +8,7 @@ use crate::network_monitor::monitor::sender::PacketSender; use crate::network_monitor::monitor::summary_producer::{NodeResult, SummaryProducer, TestReport}; use crate::network_monitor::test_packet::NodeType; use crate::network_monitor::tested_network::TestedNetwork; -use crate::storage::NodeStatusStorage; +use crate::storage::ValidatorApiStorage; use log::{debug, error, info, warn}; use std::process; use tokio::time::{sleep, Duration, Instant}; @@ -25,7 +25,7 @@ pub(super) struct Monitor { packet_sender: PacketSender, received_processor: ReceivedProcessor, summary_producer: SummaryProducer, - node_status_storage: NodeStatusStorage, + node_status_storage: ValidatorApiStorage, tested_network: TestedNetwork, run_interval: Duration, gateway_ping_interval: Duration, @@ -39,7 +39,7 @@ impl Monitor { packet_sender: PacketSender, received_processor: ReceivedProcessor, summary_producer: SummaryProducer, - node_status_storage: NodeStatusStorage, + node_status_storage: ValidatorApiStorage, tested_network: TestedNetwork, ) -> Self { Monitor { diff --git a/validator-api/src/node_status_api/mod.rs b/validator-api/src/node_status_api/mod.rs index 99daeeae48..cb16bcf6d5 100644 --- a/validator-api/src/node_status_api/mod.rs +++ b/validator-api/src/node_status_api/mod.rs @@ -9,6 +9,7 @@ use std::time::Duration; pub(crate) mod local_guard; pub(crate) mod models; pub(crate) mod routes; +pub(crate) mod uptime_updater; pub(crate) mod utils; pub(crate) const FIFTEEN_MINUTES: Duration = Duration::from_secs(900); @@ -18,7 +19,7 @@ pub(crate) const ONE_DAY: Duration = Duration::from_secs(86400); pub(crate) fn stage(database_path: PathBuf) -> AdHoc { AdHoc::on_ignite("SQLx Stage", |rocket| async { rocket - .attach(storage::NodeStatusStorage::stage(database_path)) + .attach(storage::ValidatorApiStorage::stage(database_path)) .mount( "/v1/status", routes![ diff --git a/validator-api/src/node_status_api/models.rs b/validator-api/src/node_status_api/models.rs index d39d8239b0..308e3a91d1 100644 --- a/validator-api/src/node_status_api/models.rs +++ b/validator-api/src/node_status_api/models.rs @@ -213,12 +213,12 @@ pub struct HistoricalUptime { } pub(crate) struct ErrorResponse { - error: NodeStatusApiError, + error: ValidatorApiStorageError, status: Status, } impl ErrorResponse { - pub(crate) fn new(error: NodeStatusApiError, status: Status) -> Self { + pub(crate) fn new(error: ValidatorApiStorageError, status: Status) -> Self { ErrorResponse { error, status } } } @@ -235,7 +235,7 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for ErrorResponse { } #[derive(Debug)] -pub enum NodeStatusApiError { +pub enum ValidatorApiStorageError { MixnodeReportNotFound(String), GatewayReportNotFound(String), MixnodeUptimeHistoryNotFound(String), @@ -245,30 +245,30 @@ pub enum NodeStatusApiError { InternalDatabaseError, } -impl Display for NodeStatusApiError { +impl Display for ValidatorApiStorageError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - NodeStatusApiError::MixnodeReportNotFound(identity) => write!( + ValidatorApiStorageError::MixnodeReportNotFound(identity) => write!( f, "Could not find status report associated with mixnode {}", identity ), - NodeStatusApiError::GatewayReportNotFound(identity) => write!( + ValidatorApiStorageError::GatewayReportNotFound(identity) => write!( f, "Could not find status report associated with gateway {}", identity ), - NodeStatusApiError::MixnodeUptimeHistoryNotFound(identity) => write!( + ValidatorApiStorageError::MixnodeUptimeHistoryNotFound(identity) => write!( f, "Could not find uptime history associated with mixnode {}", identity ), - NodeStatusApiError::GatewayUptimeHistoryNotFound(identity) => write!( + ValidatorApiStorageError::GatewayUptimeHistoryNotFound(identity) => write!( f, "Could not find uptime history associated with gateway {}", identity ), - NodeStatusApiError::InternalDatabaseError => { + ValidatorApiStorageError::InternalDatabaseError => { write!(f, "The internal database has experienced an issue") } } diff --git a/validator-api/src/node_status_api/routes.rs b/validator-api/src/node_status_api/routes.rs index e32f4fba75..756f10a9a2 100644 --- a/validator-api/src/node_status_api/routes.rs +++ b/validator-api/src/node_status_api/routes.rs @@ -5,14 +5,14 @@ use crate::node_status_api::models::{ ErrorResponse, GatewayStatusReport, GatewayUptimeHistory, MixnodeStatusReport, MixnodeUptimeHistory, }; -use crate::storage::NodeStatusStorage; +use crate::storage::ValidatorApiStorage; use rocket::http::Status; use rocket::serde::json::Json; use rocket::State; #[get("/mixnode//report")] pub(crate) async fn mixnode_report( - storage: &State, + storage: &State, pubkey: &str, ) -> Result, ErrorResponse> { storage @@ -24,7 +24,7 @@ pub(crate) async fn mixnode_report( #[get("/gateway//report")] pub(crate) async fn gateway_report( - storage: &State, + storage: &State, pubkey: &str, ) -> Result, ErrorResponse> { storage @@ -36,7 +36,7 @@ pub(crate) async fn gateway_report( #[get("/mixnode//history")] pub(crate) async fn mixnode_uptime_history( - storage: &State, + storage: &State, pubkey: &str, ) -> Result, ErrorResponse> { storage @@ -48,7 +48,7 @@ pub(crate) async fn mixnode_uptime_history( #[get("/gateway//history")] pub(crate) async fn gateway_uptime_history( - storage: &State, + storage: &State, pubkey: &str, ) -> Result, ErrorResponse> { storage diff --git a/validator-api/src/node_status_api/uptime_updater.rs b/validator-api/src/node_status_api/uptime_updater.rs new file mode 100644 index 0000000000..417a9a30b2 --- /dev/null +++ b/validator-api/src/node_status_api/uptime_updater.rs @@ -0,0 +1,85 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::node_status_api::models::{ + GatewayStatusReport, MixnodeStatusReport, ValidatorApiStorageError, +}; +use crate::node_status_api::ONE_DAY; +use crate::storage::ValidatorApiStorage; +use log::error; +use time::OffsetDateTime; +use tokio::time::sleep; + +pub(crate) struct HistoricalUptimeUpdater { + storage: ValidatorApiStorage, +} + +impl HistoricalUptimeUpdater { + pub(crate) fn new(storage: ValidatorApiStorage) -> Self { + HistoricalUptimeUpdater { storage } + } + + /// Obtains the lists of all mixnodes and gateways that were tested at least a single time + /// in the last 24h interval. + /// + /// # Arguments + /// + /// * `now`: current time. + async fn get_active_nodes( + &self, + now: OffsetDateTime, + ) -> Result<(Vec, Vec), ValidatorApiStorageError> + { + let day_ago = (now - ONE_DAY).unix_timestamp(); + let active_mixnodes = self + .storage + .get_all_active_mixnode_reports_in_interval(day_ago, now.unix_timestamp()) + .await?; + + let active_gateways = self + .storage + .get_all_active_gateway_reports_in_interval(day_ago, now.unix_timestamp()) + .await?; + + Ok((active_mixnodes, active_gateways)) + } + + async fn update_uptimes(&self) -> Result<(), ValidatorApiStorageError> { + let now = OffsetDateTime::now_utc(); + let today_iso_8601 = now.date().to_string(); + + // get nodes that were active in last 24h + let (active_mixnodes, active_gateways) = self.get_active_nodes(now).await?; + + if self + .storage + .check_if_historical_uptimes_exist_for_date(&today_iso_8601) + .await? + { + warn!("We have already updated uptimes for all nodes this day.") + } else { + info!("Updating historical daily uptimes of all nodes..."); + self.storage + .update_historical_uptimes(&today_iso_8601, &active_mixnodes, &active_gateways) + .await?; + } + + Ok(()) + } + + pub(crate) async fn run(&self) { + loop { + // start any updates a day after starting the task so that we would have complete data + sleep(ONE_DAY).await; + if let Err(err) = self.update_uptimes().await { + // 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 + ) + } + } + } +} diff --git a/validator-api/src/rewarding/error.rs b/validator-api/src/rewarding/error.rs index 7cd544868f..347fa07ad6 100644 --- a/validator-api/src/rewarding/error.rs +++ b/validator-api/src/rewarding/error.rs @@ -1,7 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::node_status_api::models::NodeStatusApiError; +use crate::node_status_api::models::ValidatorApiStorageError; use thiserror::Error; use validator_client::nymd::error::NymdError; use validator_client::ValidatorClientError; @@ -19,7 +19,7 @@ pub(crate) enum RewardingError { // The inner error should be modified at some point... #[error("We run into storage issues - {0}")] - StorageError(NodeStatusApiError), + StorageError(ValidatorApiStorageError), #[error("Failed to query the smart contract - {0}")] ValidatorClientError(ValidatorClientError), @@ -31,8 +31,8 @@ impl From for RewardingError { } } -impl From for RewardingError { - fn from(err: NodeStatusApiError) -> Self { +impl From for RewardingError { + fn from(err: ValidatorApiStorageError) -> Self { RewardingError::StorageError(err) } } diff --git a/validator-api/src/rewarding/mod.rs b/validator-api/src/rewarding/mod.rs index ba6d33cd29..81d6aaacae 100644 --- a/validator-api/src/rewarding/mod.rs +++ b/validator-api/src/rewarding/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::cache::ValidatorCache; -use crate::node_status_api::models::{GatewayStatusReport, MixnodeStatusReport, Uptime}; +use crate::node_status_api::models::{MixnodeStatusReport, Uptime}; use crate::node_status_api::ONE_DAY; use crate::nymd_client::Client; use crate::rewarding::epoch::Epoch; @@ -10,7 +10,7 @@ use crate::rewarding::error::RewardingError; use crate::storage::models::{ FailedMixnodeRewardChunk, PossiblyUnrewardedMixnode, RewardingReport, }; -use crate::storage::NodeStatusStorage; +use crate::storage::ValidatorApiStorage; use log::{error, info}; use mixnet_contract::{ExecuteMsg, IdentityKey}; use std::collections::HashMap; @@ -72,7 +72,7 @@ impl<'a> From<&'a MixnodeToReward> for ExecuteMsg { pub(crate) struct Rewarder { nymd_client: Client, validator_cache: ValidatorCache, - storage: NodeStatusStorage, + storage: ValidatorApiStorage, /// The first epoch of the current length. first_epoch: Epoch, @@ -91,7 +91,7 @@ impl Rewarder { pub(crate) fn new( nymd_client: Client, validator_cache: ValidatorCache, - storage: NodeStatusStorage, + storage: ValidatorApiStorage, first_epoch: Epoch, expected_epoch_monitor_runs: usize, minimum_epoch_monitor_threshold: u8, @@ -223,33 +223,23 @@ impl Rewarder { Ok(eligible_nodes) } - /// Obtains the lists of all mixnodes and gateways that were tested at least a single time + /// Obtains the lists of all mixnodes that were tested at least a single time /// by the network monitor in the specified epoch. /// /// # Arguments /// /// * `epoch`: the specified epoch. - async fn get_active_monitor_nodes( + async fn get_active_monitor_mixnodes( &self, epoch: Epoch, - ) -> Result<(Vec, Vec), RewardingError> { - let active_mixnodes = self + ) -> Result, RewardingError> { + Ok(self .storage .get_all_active_mixnode_reports_in_interval( epoch.start_unix_timestamp(), epoch.end_unix_timestamp(), ) - .await?; - - let active_gateways = self - .storage - .get_all_active_gateway_reports_in_interval( - epoch.start_unix_timestamp(), - epoch.end_unix_timestamp(), - ) - .await?; - - Ok((active_mixnodes, active_gateways)) + .await?) } /// Using the list of mixnodes eligible for rewards, chunks it into pre-defined sized-chunks @@ -511,8 +501,7 @@ impl Rewarder { ); // get nodes that were active during the epoch - let (active_monitor_mixnodes, active_monitor_gateways) = - self.get_active_monitor_nodes(epoch).await?; + let active_monitor_mixnodes = self.get_active_monitor_mixnodes(epoch).await?; // insert information about beginning the procedure (so that if we crash during it, // we wouldn't attempt to possibly double reward operators) @@ -540,32 +529,11 @@ impl Rewarder { } } - // TODO: again, this assumes 24h epochs. - let epoch_iso_8601 = epoch.start().date().to_string(); - let two_days_ago = (epoch.start() - 2 * ONE_DAY).unix_timestamp(); - - // NOTE: this works under assumption that epochs are 24h in length. - // If this changes then the historical uptime updates should be performed - // on a timer in another task - if self - .storage - .check_if_historical_uptimes_exist_for_date(&epoch_iso_8601) - .await? - { - error!("We have already updated uptimes for all nodes this day. If you're seeing this warning, it's likely rewards were given out twice this day!") - } else { - info!( - "Updating historical daily uptimes of all nodes and purging old status reports..." - ); - self.storage - .update_historical_uptimes( - &epoch_iso_8601, - &active_monitor_mixnodes, - &active_monitor_gateways, - ) - .await?; - self.storage.purge_old_statuses(two_days_ago).await?; - } + // since we have already performed rewards, purge everything older than the end of this epoch + // (+one day of buffer) as we're never going to need it again (famous last words...) + // note that usually end of epoch is equal to the current time + let cutoff = (epoch.end() - ONE_DAY).unix_timestamp(); + self.storage.purge_old_statuses(cutoff).await?; Ok(()) } diff --git a/validator-api/src/storage/mod.rs b/validator-api/src/storage/mod.rs index e0ca1a5ffc..2954af2f35 100644 --- a/validator-api/src/storage/mod.rs +++ b/validator-api/src/storage/mod.rs @@ -4,7 +4,7 @@ use crate::network_monitor::monitor::summary_producer::NodeResult; use crate::node_status_api::models::{ GatewayStatusReport, GatewayUptimeHistory, MixnodeStatusReport, MixnodeUptimeHistory, - NodeStatusApiError, + ValidatorApiStorageError, }; use crate::node_status_api::{ONE_DAY, ONE_HOUR}; use crate::storage::manager::StorageManager; @@ -26,11 +26,11 @@ pub(crate) type UnixTimestamp = i64; // note that clone here is fine as upon cloning the same underlying pool will be used #[derive(Clone)] -pub(crate) struct NodeStatusStorage { +pub(crate) struct ValidatorApiStorage { manager: StorageManager, } -impl NodeStatusStorage { +impl ValidatorApiStorage { async fn init(rocket: Rocket, database_path: PathBuf) -> fairing::Result { // TODO: we can inject here more stuff based on our validator-api global config // struct. Maybe different pool size or timeout intervals? @@ -57,7 +57,7 @@ impl NodeStatusStorage { info!("Database migration finished!"); - let storage = NodeStatusStorage { + let storage = ValidatorApiStorage { manager: StorageManager { connection_pool }, }; @@ -66,7 +66,7 @@ impl NodeStatusStorage { pub(crate) fn stage(database_path: PathBuf) -> AdHoc { AdHoc::try_on_ignite("SQLx Database", |rocket| { - NodeStatusStorage::init(rocket, database_path) + ValidatorApiStorage::init(rocket, database_path) }) } @@ -83,18 +83,18 @@ impl NodeStatusStorage { &self, identity: &str, since: UnixTimestamp, - ) -> Result<(Vec, Vec), NodeStatusApiError> { + ) -> Result<(Vec, Vec), ValidatorApiStorageError> { let ipv4_statuses = self .manager .get_mixnode_ipv4_statuses_since(identity, since) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; let ipv6_statuses = self .manager .get_mixnode_ipv6_statuses_since(identity, since) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; Ok((ipv4_statuses, ipv6_statuses)) } @@ -112,18 +112,18 @@ impl NodeStatusStorage { &self, identity: &str, since: UnixTimestamp, - ) -> Result<(Vec, Vec), NodeStatusApiError> { + ) -> Result<(Vec, Vec), ValidatorApiStorageError> { let ipv4_statuses = self .manager .get_gateway_ipv4_statuses_since(identity, since) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; let ipv6_statuses = self .manager .get_gateway_ipv6_statuses_since(identity, since) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; Ok((ipv4_statuses, ipv6_statuses)) } @@ -132,7 +132,7 @@ impl NodeStatusStorage { pub(crate) async fn construct_mixnode_report( &self, identity: &str, - ) -> Result { + ) -> Result { let now = OffsetDateTime::now_utc(); let day_ago = (now - ONE_DAY).unix_timestamp(); let hour_ago = (now - ONE_HOUR).unix_timestamp(); @@ -141,7 +141,7 @@ impl NodeStatusStorage { // if we have no statuses, the node doesn't exist (or monitor is down), but either way, we can't make a report if ipv4_statuses.is_empty() { - return Err(NodeStatusApiError::MixnodeReportNotFound( + return Err(ValidatorApiStorageError::MixnodeReportNotFound( identity.to_owned(), )); } @@ -168,7 +168,7 @@ impl NodeStatusStorage { .manager .get_mixnode_owner(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .expect("The node doesn't have an owner even though we have status information on it!"); Ok(MixnodeStatusReport::construct_from_last_day_reports( @@ -185,7 +185,7 @@ impl NodeStatusStorage { pub(crate) async fn construct_gateway_report( &self, identity: &str, - ) -> Result { + ) -> Result { let now = OffsetDateTime::now_utc(); let day_ago = (now - ONE_DAY).unix_timestamp(); let hour_ago = (now - ONE_HOUR).unix_timestamp(); @@ -194,7 +194,7 @@ impl NodeStatusStorage { // if we have no statuses, the node doesn't exist (or monitor is down), but either way, we can't make a report if ipv4_statuses.is_empty() { - return Err(NodeStatusApiError::GatewayReportNotFound( + return Err(ValidatorApiStorageError::GatewayReportNotFound( identity.to_owned(), )); } @@ -221,7 +221,7 @@ impl NodeStatusStorage { .manager .get_gateway_owner(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .expect( "The gateway doesn't have an owner even though we have status information on it!", ); @@ -240,15 +240,15 @@ impl NodeStatusStorage { pub(crate) async fn get_mixnode_uptime_history( &self, identity: &str, - ) -> Result { + ) -> Result { let history = self .manager .get_mixnode_historical_uptimes(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; if history.is_empty() { - return Err(NodeStatusApiError::MixnodeUptimeHistoryNotFound( + return Err(ValidatorApiStorageError::MixnodeUptimeHistoryNotFound( identity.to_owned(), )); } @@ -257,7 +257,7 @@ impl NodeStatusStorage { .manager .get_mixnode_owner(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .expect("The node doesn't have an owner even though we have uptime history for it!"); Ok(MixnodeUptimeHistory::new( @@ -270,15 +270,15 @@ impl NodeStatusStorage { pub(crate) async fn get_gateway_uptime_history( &self, identity: &str, - ) -> Result { + ) -> Result { let history = self .manager .get_gateway_historical_uptimes(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; if history.is_empty() { - return Err(NodeStatusApiError::GatewayUptimeHistoryNotFound( + return Err(ValidatorApiStorageError::GatewayUptimeHistoryNotFound( identity.to_owned(), )); } @@ -287,7 +287,7 @@ impl NodeStatusStorage { .manager .get_gateway_owner(identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .expect("The gateway doesn't have an owner even though we have uptime history for it!"); Ok(GatewayUptimeHistory::new( @@ -309,7 +309,7 @@ impl NodeStatusStorage { &self, start: UnixTimestamp, end: UnixTimestamp, - ) -> Result, NodeStatusApiError> { + ) -> Result, ValidatorApiStorageError> { if (end - start) as u64 != ONE_DAY.as_secs() { warn!("Our current epoch length breaks the 24h length assumption") } @@ -324,7 +324,7 @@ impl NodeStatusStorage { .manager .get_all_active_mixnodes_statuses_in_interval(start, end) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .into_iter() .map(|statuses| { MixnodeStatusReport::construct_from_last_day_reports( @@ -354,7 +354,7 @@ impl NodeStatusStorage { &self, start: UnixTimestamp, end: UnixTimestamp, - ) -> Result, NodeStatusApiError> { + ) -> Result, ValidatorApiStorageError> { if (end - start) as u64 != ONE_DAY.as_secs() { warn!("Our current epoch length breaks the 24h length assumption") } @@ -369,7 +369,7 @@ impl NodeStatusStorage { .manager .get_all_active_gateways_statuses_in_interval(start, end) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? .into_iter() .map(|statuses| { GatewayStatusReport::construct_from_last_day_reports( @@ -392,7 +392,7 @@ impl NodeStatusStorage { &self, mixnode_results: Vec, gateway_results: Vec, - ) -> Result<(), NodeStatusApiError> { + ) -> Result<(), ValidatorApiStorageError> { info!("Submitting new node results to the database. There are {} mixnode results and {} gateway results", mixnode_results.len(), gateway_results.len()); let now = OffsetDateTime::now_utc().unix_timestamp(); @@ -400,23 +400,23 @@ impl NodeStatusStorage { self.manager .submit_mixnode_statuses(now, mixnode_results) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; self.manager .submit_gateway_statuses(now, gateway_results) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Inserts an entry to the database with the network monitor test run information /// that has occurred at this instant. - pub(crate) async fn insert_monitor_run(&self) -> Result<(), NodeStatusApiError> { + pub(crate) async fn insert_monitor_run(&self) -> Result<(), ValidatorApiStorageError> { let now = OffsetDateTime::now_utc().unix_timestamp(); self.manager .insert_monitor_run(now) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Obtains number of network monitor test runs that have occurred within the specified interval. @@ -429,26 +429,22 @@ impl NodeStatusStorage { &self, since: UnixTimestamp, until: UnixTimestamp, - ) -> Result { + ) -> Result { let run_count = self .manager .get_monitor_runs_count(since, until) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; if run_count < 0 { // I don't think it's ever possible for SQL to return a negative value from COUNT? - return Err(NodeStatusApiError::InternalDatabaseError); + return Err(ValidatorApiStorageError::InternalDatabaseError); } Ok(run_count as usize) } /// Given lists of reports of all monitor-active mixnodes and gateways, inserts the data into the - /// historical uptime tables. - /// - /// This method is called at every reward cycle. Note that currently to work as expected, it - /// assumes a 24h epoch period. If this assumption is broken, this method should be called - /// on an independent timer. + /// historical uptime tables. This method is called at a 24h timer. /// /// # Arguments /// @@ -460,7 +456,7 @@ impl NodeStatusStorage { today_iso_8601: &str, mixnode_reports: &[MixnodeStatusReport], gateway_reports: &[GatewayStatusReport], - ) -> Result<(), NodeStatusApiError> { + ) -> Result<(), ValidatorApiStorageError> { for report in mixnode_reports { // if this ever fails, we have a super weird error because we just constructed report for that node // and we never delete node data! @@ -468,7 +464,7 @@ impl NodeStatusStorage { .manager .get_mixnode_id(&report.identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? { Some(node_id) => node_id, None => { @@ -488,7 +484,7 @@ impl NodeStatusStorage { report.last_day_ipv4.u8(), ) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; } for report in gateway_reports { @@ -498,7 +494,7 @@ impl NodeStatusStorage { .manager .get_gateway_id(&report.identity) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)? + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? { Some(node_id) => node_id, None => { @@ -518,7 +514,7 @@ impl NodeStatusStorage { report.last_day_ipv4.u8(), ) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; } Ok(()) @@ -527,11 +523,11 @@ impl NodeStatusStorage { pub(crate) async fn check_if_historical_uptimes_exist_for_date( &self, date_iso_8601: &str, - ) -> Result { + ) -> Result { self.manager .check_for_historical_uptime_existence(date_iso_8601) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Removes all ipv4 and ipv6 statuses for all mixnodes and gateways that are older than the @@ -543,23 +539,23 @@ impl NodeStatusStorage { pub(crate) async fn purge_old_statuses( &self, until: UnixTimestamp, - ) -> Result<(), NodeStatusApiError> { + ) -> Result<(), ValidatorApiStorageError> { self.manager .purge_old_mixnode_ipv4_statuses(until) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; self.manager .purge_old_mixnode_ipv6_statuses(until) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; self.manager .purge_old_gateway_ipv4_statuses(until) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; self.manager .purge_old_gateway_ipv6_statuses(until) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } //////////////////////////////////////////////////////////////////////// @@ -575,11 +571,11 @@ impl NodeStatusStorage { pub(crate) async fn insert_started_epoch_rewarding( &self, epoch_timestamp: UnixTimestamp, - ) -> Result { + ) -> Result { self.manager .insert_new_epoch_rewarding(epoch_timestamp) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } // /// Tries to obtain the most recent epoch rewarding entry currently stored. @@ -604,11 +600,11 @@ impl NodeStatusStorage { pub(super) async fn get_epoch_rewarding_entry( &self, epoch_timestamp: UnixTimestamp, - ) -> Result, NodeStatusApiError> { + ) -> Result, ValidatorApiStorageError> { self.manager .get_epoch_rewarding_entry(epoch_timestamp) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Sets the `finished` field on the epoch rewarding to true and inserts the rewarding report into @@ -620,16 +616,16 @@ impl NodeStatusStorage { pub(crate) async fn finish_rewarding_epoch_and_insert_report( &self, report: RewardingReport, - ) -> Result<(), NodeStatusApiError> { + ) -> Result<(), ValidatorApiStorageError> { self.manager .update_finished_epoch_rewarding(report.epoch_rewarding_id) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; self.manager .insert_rewarding_report(report) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Inserts new failed mixnode reward chunk information into the database. @@ -641,11 +637,11 @@ impl NodeStatusStorage { pub(crate) async fn insert_failed_mixnode_reward_chunk( &self, failed_chunk: FailedMixnodeRewardChunk, - ) -> Result { + ) -> Result { self.manager .insert_failed_mixnode_reward_chunk(failed_chunk) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } /// Inserts information into the database about a mixnode that might have been unfairly unrewarded this epoch. @@ -656,10 +652,10 @@ impl NodeStatusStorage { pub(crate) async fn insert_possibly_unrewarded_mixnode( &self, mixnode: PossiblyUnrewardedMixnode, - ) -> Result<(), NodeStatusApiError> { + ) -> Result<(), ValidatorApiStorageError> { self.manager .insert_possibly_unrewarded_mixnode(mixnode) .await - .map_err(|_| NodeStatusApiError::InternalDatabaseError) + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) } }