Feature/explorer 2979 (#3147)

* additional unfiltered endpoints for nym-api

* add poor performance UI

* display appropriate UI when node is blacklisted

* update explorer api with blacklisted nodes

* add new unfiltered endpoint

add new unfiltered endpoint

* show blacklisted detail even when node description is unavailable

remove console.log

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
This commit is contained in:
Fouad
2023-03-08 15:15:32 +00:00
committed by GitHub
parent d315a2a91b
commit 3b97844310
20 changed files with 211 additions and 106 deletions
+13 -3
View File
@@ -89,10 +89,15 @@ impl NodeStatusCache {
}
}
pub(crate) async fn mixnodes_annotated(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
pub(crate) async fn mixnodes_annotated_full(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
self.get(|c| c.mixnodes_annotated.clone()).await
}
pub(crate) async fn mixnodes_annotated_filtered(&self) -> Option<Vec<MixNodeBondAnnotated>> {
let full = self.mixnodes_annotated_full().await?;
Some(full.value.into_iter().filter(|m| !m.blacklisted).collect())
}
pub(crate) async fn rewarded_set_annotated(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
self.get(|c| c.rewarded_set_annotated.clone()).await
}
@@ -101,10 +106,15 @@ impl NodeStatusCache {
self.get(|c| c.active_set_annotated.clone()).await
}
pub(crate) async fn gateways_annotated(&self) -> Option<Cache<Vec<GatewayBondAnnotated>>> {
pub(crate) async fn gateways_annotated_full(&self) -> Option<Cache<Vec<GatewayBondAnnotated>>> {
self.get(|c| c.gateways_annotated.clone()).await
}
pub(crate) async fn gateways_annotated_filtered(&self) -> Option<Vec<GatewayBondAnnotated>> {
let full = self.gateways_annotated_full().await?;
Some(full.value.into_iter().filter(|m| !m.blacklisted).collect())
}
pub(crate) async fn inclusion_probabilities(&self) -> Option<Cache<InclusionProbabilities>> {
self.get(|c| c.inclusion_probabilities.clone()).await
}
@@ -126,7 +136,7 @@ impl NodeStatusCache {
return (Some(bond.clone()), MixnodeStatus::Standby);
}
let all_bonded = &self.mixnodes_annotated().await.unwrap().into_inner();
let all_bonded = &self.mixnodes_annotated_filtered().await.unwrap();
if let Some(bond) = all_bonded.iter().find(|mix| mix.mix_id() == mix_id) {
(Some(bond.clone()), MixnodeStatus::Inactive)
} else {
+5 -1
View File
@@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{reward_params::Performance, Interval, MixId};
use nym_mixnet_contract_common::{
GatewayBond, IdentityKey, MixNodeDetails, RewardedSetNodeStatus, RewardingParams,
};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
pub(super) fn to_rewarded_set_node_status(
rewarded_set: &[MixNodeDetails],
@@ -84,6 +84,7 @@ pub(super) async fn annotate_nodes_with_details(
current_interval: Interval,
rewarded_set: &HashMap<MixId, RewardedSetNodeStatus>,
mix_to_family: Vec<(IdentityKey, FamilyHead)>,
blacklist: &HashSet<MixId>,
) -> Vec<MixNodeBondAnnotated> {
let mix_to_family = mix_to_family
.into_iter()
@@ -135,6 +136,7 @@ pub(super) async fn annotate_nodes_with_details(
.cloned();
annotated.push(MixNodeBondAnnotated {
blacklisted: blacklist.contains(&mixnode.mix_id()),
mixnode_details: mixnode,
stake_saturation,
uncapped_stake_saturation,
@@ -152,6 +154,7 @@ pub(crate) async fn annotate_gateways_with_details(
storage: &Option<NymApiStorage>,
gateway_bonds: Vec<GatewayBond>,
current_interval: Interval,
blacklist: &HashSet<IdentityKey>,
) -> Vec<GatewayBondAnnotated> {
let mut annotated = Vec::new();
for gateway_bond in gateway_bonds {
@@ -175,6 +178,7 @@ pub(crate) async fn annotate_gateways_with_details(
.unwrap_or_default();
annotated.push(GatewayBondAnnotated {
blacklisted: blacklist.contains(&gateway_bond.gateway.identity_key),
gateway_bond,
performance,
node_performance,
+14 -4
View File
@@ -109,13 +109,17 @@ impl NodeStatusCacheRefresher {
log::info!("Updating node status cache");
// Fetch contract cache data to work with
let mixnode_details = self.contract_cache.mixnodes().await;
let mixnode_details = self.contract_cache.mixnodes_all().await;
let interval_reward_params = self.contract_cache.interval_reward_params().await;
let current_interval = self.contract_cache.current_interval().await;
let rewarded_set = self.contract_cache.rewarded_set().await;
let active_set = self.contract_cache.active_set().await;
let mix_to_family = self.contract_cache.mix_to_family().await;
let gateway_bonds = self.contract_cache.gateways().await;
let gateway_bonds = self.contract_cache.gateways_all().await;
// get blacklists
let mixnodes_blacklist = self.contract_cache.mixnodes_blacklist().await;
let gateways_blacklist = self.contract_cache.gateways_blacklist().await;
let interval_reward_params =
interval_reward_params.ok_or(NodeStatusCacheError::SourceDataMissing)?;
@@ -140,6 +144,7 @@ impl NodeStatusCacheRefresher {
current_interval,
&rewarded_set_node_status,
mix_to_family.to_vec(),
&mixnodes_blacklist,
)
.await;
@@ -147,8 +152,13 @@ impl NodeStatusCacheRefresher {
let (rewarded_set, active_set) =
split_into_active_and_rewarded_set(&mixnodes_annotated, &rewarded_set_node_status);
let gateways_annotated =
annotate_gateways_with_details(&self.storage, gateway_bonds, current_interval).await;
let gateways_annotated = annotate_gateways_with_details(
&self.storage,
gateway_bonds,
current_interval,
&gateways_blacklist,
)
.await;
// Update the cache
self.cache
+35 -13
View File
@@ -24,17 +24,19 @@ async fn get_gateway_bond_annotated(
cache: &NodeStatusCache,
identity: &str,
) -> Result<GatewayBondAnnotated, ErrorResponse> {
let gateways = cache.gateways_annotated().await.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
let gateways = cache
.gateways_annotated_filtered()
.await
.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
gateways
.into_inner()
.into_iter()
.find(|gateway| gateway.identity() == identity)
.ok_or(ErrorResponse::new(
"mixnode bond not found",
"gateway bond not found",
Status::NotFound,
))
}
@@ -43,13 +45,15 @@ async fn get_mixnode_bond_annotated(
cache: &NodeStatusCache,
mix_id: MixId,
) -> Result<MixNodeBondAnnotated, ErrorResponse> {
let mixnodes = cache.mixnodes_annotated().await.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
let mixnodes = cache
.mixnodes_annotated_filtered()
.await
.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
mixnodes
.into_inner()
.into_iter()
.find(|mixnode| mixnode.mix_id() == mix_id)
.ok_or(ErrorResponse::new(
@@ -374,7 +378,16 @@ pub(crate) async fn _get_mixnode_inclusion_probabilities(
pub(crate) async fn _get_mixnodes_detailed(cache: &NodeStatusCache) -> Vec<MixNodeBondAnnotated> {
cache
.mixnodes_annotated()
.mixnodes_annotated_filtered()
.await
.unwrap_or_default()
}
pub(crate) async fn _get_mixnodes_detailed_unfiltered(
cache: &NodeStatusCache,
) -> Vec<MixNodeBondAnnotated> {
cache
.mixnodes_annotated_full()
.await
.unwrap_or_default()
.into_inner()
@@ -400,7 +413,16 @@ pub(crate) async fn _get_active_set_detailed(cache: &NodeStatusCache) -> Vec<Mix
pub(crate) async fn _get_gateways_detailed(cache: &NodeStatusCache) -> Vec<GatewayBondAnnotated> {
cache
.gateways_annotated()
.gateways_annotated_filtered()
.await
.unwrap_or_default()
}
pub(crate) async fn _get_gateways_detailed_unfiltered(
cache: &NodeStatusCache,
) -> Vec<GatewayBondAnnotated> {
cache
.gateways_annotated_full()
.await
.unwrap_or_default()
.into_inner()
+2
View File
@@ -48,9 +48,11 @@ pub(crate) fn node_status_routes(
routes::get_gateway_avg_uptime,
routes::get_mixnode_inclusion_probabilities,
routes::get_mixnodes_detailed,
routes::get_mixnodes_detailed_unfiltered,
routes::get_rewarded_set_detailed,
routes::get_active_set_detailed,
routes::get_gateways_detailed,
routes::get_gateways_detailed_unfiltered,
]
} else {
// in the minimal variant we would not have access to endpoints relying on existence
+21 -5
View File
@@ -6,11 +6,11 @@ use super::NodeStatusCache;
use crate::node_status_api::helpers::{
_compute_mixnode_reward_estimation, _gateway_core_status_count, _gateway_report,
_gateway_uptime_history, _get_active_set_detailed, _get_gateway_avg_uptime,
_get_mixnode_avg_uptime, _get_mixnode_inclusion_probabilities,
_get_mixnode_inclusion_probability, _get_mixnode_reward_estimation,
_get_mixnode_stake_saturation, _get_mixnode_status, _get_mixnodes_detailed,
_get_rewarded_set_detailed, _mixnode_core_status_count, _mixnode_report,
_mixnode_uptime_history,
_get_gateways_detailed_unfiltered, _get_mixnode_avg_uptime,
_get_mixnode_inclusion_probabilities, _get_mixnode_inclusion_probability,
_get_mixnode_reward_estimation, _get_mixnode_stake_saturation, _get_mixnode_status,
_get_mixnodes_detailed, _get_mixnodes_detailed_unfiltered, _get_rewarded_set_detailed,
_mixnode_core_status_count, _mixnode_report, _mixnode_uptime_history,
};
use crate::node_status_api::models::ErrorResponse;
use crate::storage::NymApiStorage;
@@ -188,6 +188,14 @@ pub async fn get_mixnodes_detailed(
Json(_get_mixnodes_detailed(cache).await)
}
#[openapi(tag = "status")]
#[get("/mixnodes/detailed-unfiltered")]
pub async fn get_mixnodes_detailed_unfiltered(
cache: &State<NodeStatusCache>,
) -> Json<Vec<MixNodeBondAnnotated>> {
Json(_get_mixnodes_detailed_unfiltered(cache).await)
}
#[openapi(tag = "status")]
#[get("/mixnodes/rewarded/detailed")]
pub async fn get_rewarded_set_detailed(
@@ -211,3 +219,11 @@ pub async fn get_gateways_detailed(
) -> Json<Vec<GatewayBondAnnotated>> {
Json(_get_gateways_detailed(cache).await)
}
#[openapi(tag = "status")]
#[get("/gateways/detailed-unfiltered")]
pub async fn get_gateways_detailed_unfiltered(
cache: &State<NodeStatusCache>,
) -> Json<Vec<GatewayBondAnnotated>> {
Json(_get_gateways_detailed_unfiltered(cache).await)
}