Files
nym/nym-api/src/node_performance/contract_cache/data.rs
T
Jędrzej Stuczyński d0692a567a feat: basic performance contract integration [within Nym API] (#5871)
* 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
2025-07-01 11:29:50 +01:00

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 }
}
}