d0692a567a
* renamed nym-api config fields * decouple rewarder startup from network monitor * additional sections in nym-api config * removed vesting queries in circulating supply calculator * added memoized field for last submitted performance measurement * wip: performance contract refresher * cleaned up various contract caches * modified cache refresher to allow passing update fn * implement performance cache refreshing * updated lefthook.yml to run cargo fmt * impl NodePerformanceProvider trait * dynamically using specific performance provider * pre warm up performance contract cache and forbid the mode if its empty * clippy * introduce fallback setting for performance contract if value for given epoch is not available * move some functions around
89 lines
3.0 KiB
Rust
89 lines
3.0 KiB
Rust
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
use crate::node_performance::provider::PerformanceRetrievalFailure;
|
|
use nym_api_requests::models::RoutingScore;
|
|
use nym_contracts_common::NaiveFloat;
|
|
use nym_mixnet_contract_common::reward_params::Performance;
|
|
use nym_mixnet_contract_common::{EpochId, NodeId};
|
|
use nym_validator_client::nyxd::contract_traits::performance_query_client::NodePerformance;
|
|
use std::collections::{BTreeMap, HashMap};
|
|
|
|
pub(crate) struct PerformanceContractEpochCacheData {
|
|
pub(crate) epoch_id: EpochId,
|
|
pub(crate) median_performance: HashMap<NodeId, Performance>,
|
|
}
|
|
|
|
impl PerformanceContractEpochCacheData {
|
|
pub(crate) fn from_node_performance(
|
|
performance: Vec<NodePerformance>,
|
|
epoch_id: EpochId,
|
|
) -> Self {
|
|
let median_performance = performance
|
|
.into_iter()
|
|
.map(|node_performance| (node_performance.node_id, node_performance.performance))
|
|
.collect();
|
|
PerformanceContractEpochCacheData {
|
|
epoch_id,
|
|
median_performance,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) struct PerformanceContractCacheData {
|
|
pub(crate) epoch_performance: BTreeMap<EpochId, PerformanceContractEpochCacheData>,
|
|
}
|
|
|
|
impl PerformanceContractCacheData {
|
|
pub(crate) fn update(
|
|
&mut self,
|
|
update: PerformanceContractEpochCacheData,
|
|
values_to_retain: usize,
|
|
) {
|
|
self.epoch_performance.insert(update.epoch_id, update);
|
|
if self.epoch_performance.len() > values_to_retain {
|
|
// remove the oldest entry, i.e. one with the lowest epoch id
|
|
self.epoch_performance.pop_first();
|
|
}
|
|
}
|
|
|
|
pub(crate) fn node_routing_score(
|
|
&self,
|
|
node_id: NodeId,
|
|
epoch_id: EpochId,
|
|
) -> Result<RoutingScore, PerformanceRetrievalFailure> {
|
|
// TODO: somehow send a signal to refresh this epoch
|
|
let epoch_scores = self.epoch_performance.get(&epoch_id).ok_or_else(|| {
|
|
PerformanceRetrievalFailure::new(
|
|
node_id,
|
|
epoch_id,
|
|
format!("no cached performance results for epoch {epoch_id}"),
|
|
)
|
|
})?;
|
|
|
|
let node_score = epoch_scores
|
|
.median_performance
|
|
.get(&node_id)
|
|
.ok_or_else(|| {
|
|
PerformanceRetrievalFailure::new(
|
|
node_id,
|
|
epoch_id,
|
|
format!(
|
|
"no cached performance results for node {node_id} for epoch {epoch_id}"
|
|
),
|
|
)
|
|
})?;
|
|
|
|
Ok(RoutingScore::new(node_score.naive_to_f64()))
|
|
}
|
|
}
|
|
|
|
// needed for cache initialisation
|
|
impl From<PerformanceContractEpochCacheData> for PerformanceContractCacheData {
|
|
fn from(cache_data: PerformanceContractEpochCacheData) -> Self {
|
|
let mut epoch_performance = BTreeMap::new();
|
|
epoch_performance.insert(cache_data.epoch_id, cache_data);
|
|
PerformanceContractCacheData { epoch_performance }
|
|
}
|
|
}
|