Skip to content
3 changes: 2 additions & 1 deletion rs/nns/governance/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7859,7 +7859,8 @@ impl Governance {
"get_node_providers_rewards",
Encode!(&GetNodeProvidersRewardsRequest {
from_day: start_date,
to_day: end_date
to_day: end_date,
algorithm_version: None
})
.unwrap(),
)
Expand Down
15 changes: 15 additions & 0 deletions rs/node_rewards/canister/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,23 @@ pub mod providers_rewards;
mod api_native_conversion;

use chrono::{DateTime, Datelike, NaiveDate};
use rewards_calculation::AlgorithmVersion;
use rewards_calculation::performance_based_algorithm::v1::RewardsCalculationV1;
use std::fmt::Display;

#[derive(candid::CandidType, candid::Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub struct RewardsCalculationAlgorithmVersion {
pub version: u32,
}

impl Default for RewardsCalculationAlgorithmVersion {
fn default() -> Self {
Self {
version: RewardsCalculationV1::VERSION,
}
}
}

// These are API-facing types with all fields wrapped in `Option`
// to ensure deserialization always works
// in the future without breaking clients that consume the API.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
pub use crate::DateUtc;
use crate::RewardsCalculationAlgorithmVersion;
use candid::{CandidType, Deserialize};
use ic_base_types::{PrincipalId, SubnetId};
use std::collections::BTreeMap;

#[derive(CandidType, Clone, Deserialize)]
pub struct GetNodeProvidersRewardsCalculationRequest {
pub day: DateUtc,
pub algorithm_version: Option<RewardsCalculationAlgorithmVersion>,
}

// TODO: Remove useless level of indirection: https://github.com/dfinity/ic/pull/7071/files#r2406450031
Expand Down
4 changes: 3 additions & 1 deletion rs/node_rewards/canister/api/src/providers_rewards.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use crate::DateUtc;
use crate::{DateUtc, RewardsCalculationAlgorithmVersion};
use candid::{CandidType, Deserialize, Principal};
use std::collections::BTreeMap;

#[derive(CandidType, Clone, Deserialize)]
pub struct GetNodeProvidersRewardsRequest {
pub from_day: DateUtc,
pub to_day: DateUtc,
pub algorithm_version: Option<RewardsCalculationAlgorithmVersion>,
}
pub type GetNodeProvidersRewardsResponse = Result<NodeProvidersRewards, String>;

#[derive(CandidType, Deserialize, Debug, PartialEq)]
pub struct NodeProvidersRewards {
pub rewards_xdr_permyriad: BTreeMap<Principal, u64>,
pub algorithm_version: RewardsCalculationAlgorithmVersion,
}
7 changes: 7 additions & 0 deletions rs/node_rewards/canister/node-rewards-canister.did
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type DateUtc = record {
year: opt nat32;
};

type RewardsCalculationVersion = record {
version: nat32;
};

type NodeMetricsDaily = record {
subnet_assigned: opt principal;
subnet_assigned_failure_rate: opt float64;
Expand Down Expand Up @@ -64,6 +68,7 @@ type GetNodeProvidersRewardsCalculationResponse = variant { Ok: DailyResults; Er

type GetNodeProvidersRewardsCalculationRequest = record {
day: DateUtc;
algorithm_version: opt RewardsCalculationVersion;
};

// get_node_providers_rewards
Expand All @@ -73,11 +78,13 @@ type NodeProvidersRewards = record {
principal;
nat64;
};
algorithm_version: RewardsCalculationVersion;
};

type GetNodeProvidersRewardsRequest = record {
from_day: DateUtc;
to_day: DateUtc;
algorithm_version: opt RewardsCalculationVersion;
};

type GetNodeProvidersRewardsResponse = variant { Ok: NodeProvidersRewards; Err: text };
Expand Down
22 changes: 20 additions & 2 deletions rs/node_rewards/canister/src/canister/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::registry_querier::RegistryQuerier;
use crate::storage::{NaiveDateStorable, VM};
use chrono::{DateTime, NaiveDate};
use ic_base_types::{PrincipalId, SubnetId};
use ic_node_rewards_canister_api::RewardsCalculationAlgorithmVersion;
use ic_node_rewards_canister_api::monthly_rewards::{
GetNodeProvidersMonthlyXdrRewardsRequest, GetNodeProvidersMonthlyXdrRewardsResponse,
NodeProvidersMonthlyXdrRewards,
Expand All @@ -25,6 +26,7 @@ use ic_registry_keys::{
use ic_registry_node_provider_rewards::{RewardsPerNodeProvider, calculate_rewards_v0};
use ic_stable_structures::StableCell;
use ic_types::{RegistryVersion, Time};
use rewards_calculation::AlgorithmVersion;
use rewards_calculation::performance_based_algorithm::results::RewardsCalculatorResults;
use rewards_calculation::performance_based_algorithm::v1::RewardsCalculationV1;
use rewards_calculation::types::{NodeMetricsDailyRaw, RewardableNode};
Expand Down Expand Up @@ -165,8 +167,18 @@ impl NodeRewardsCanister {
let end_day = NaiveDate::try_from(request.to_day)?;
self.validate_reward_period(start_day, end_day)?;

RewardsCalculationV1::calculate_rewards(start_day, end_day, self)
.map_err(|e| format!("Could not calculate rewards: {e:?}"))
// Default to currently used algorithm
let rewards_calculator_version = request.algorithm_version.unwrap_or_default();

match rewards_calculator_version.version {
RewardsCalculationV1::VERSION => {
RewardsCalculationV1::calculate_rewards(start_day, end_day, self)
.map_err(|e| format!("Could not calculate rewards: {e:?}"))
}
_ => Err(format!(
"Rewards Calculation Version: {rewards_calculator_version:?} is not supported"
)),
}
}
}

Expand Down Expand Up @@ -291,7 +303,12 @@ impl NodeRewardsCanister {
.map(|(k, v)| (k.0, v))
.collect();

let algorithm_version = RewardsCalculationAlgorithmVersion {
version: result.algorithm_version,
};

Ok(NodeProvidersRewards {
algorithm_version,
rewards_xdr_permyriad,
})
}
Expand All @@ -303,6 +320,7 @@ impl NodeRewardsCanister {
let request_inner = GetNodeProvidersRewardsRequest {
from_day: request.day,
to_day: request.day,
algorithm_version: request.algorithm_version,
};
let mut result =
canister.with_borrow(|canister| canister.calculate_rewards(request_inner))?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::pb::v1::{NodeMetrics, SubnetMetricsKey, SubnetMetricsValue};
use crate::storage::NaiveDateStorable;
use futures_util::FutureExt;
use ic_nervous_system_canisters::registry::fake::FakeRegistry;
use ic_node_rewards_canister_api::RewardsCalculationAlgorithmVersion;
use ic_node_rewards_canister_api::providers_rewards::{
GetNodeProvidersRewardsRequest, NodeProvidersRewards,
};
Expand Down Expand Up @@ -318,11 +319,13 @@ fn test_get_node_providers_rewards() {
let request = GetNodeProvidersRewardsRequest {
from_day: from.into(),
to_day: to.into(),
algorithm_version: None,
};
let result_endpoint =
NodeRewardsCanister::get_node_providers_rewards(&CANISTER_TEST, request.clone());

let expected = NodeProvidersRewards {
algorithm_version: RewardsCalculationAlgorithmVersion::default(),
rewards_xdr_permyriad: btreemap! {
test_provider_id(1).0 => 137200,
test_provider_id(2).0 => 10000,
Expand Down
1 change: 1 addition & 0 deletions rs/node_rewards/canister/src/timer_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ impl RecurringSyncTask for GetNodeProvidersRewardsInstructionsExporter {
let request = GetNodeProvidersRewardsRequest {
from_day: DateUtc::from(from_day),
to_day: DateUtc::from(to_day),
algorithm_version: None,
};

let instruction_counter = telemetry::InstructionCounter::default();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ async fn get_node_providers_rewards_calculation_is_only_callable_in_nonreplicate
pocket_ic.tick().await;
let day = DateUtc::from_unix_timestamp_nanoseconds(past_time_nanos);

let request = GetNodeProvidersRewardsCalculationRequest { day };
let request = GetNodeProvidersRewardsCalculationRequest {
day,
algorithm_version: None,
};

// Non-replicated query call is allowed.
let err = query_candid::<_, (GetNodeProvidersRewardsCalculationResponse,)>(
Expand Down
4 changes: 4 additions & 0 deletions rs/node_rewards/rewards_calculation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
pub mod performance_based_algorithm;
pub mod types;

pub trait AlgorithmVersion {
const VERSION: u32;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::AlgorithmVersion;
use crate::performance_based_algorithm::results::{
DailyNodeFailureRate, DailyNodeProviderRewards, DailyNodeRewards, DailyResults,
NodeMetricsDaily, NodeTypeRegionBaseRewards, RewardsCalculatorResults, Type3RegionBaseRewards,
Expand Down Expand Up @@ -84,7 +85,7 @@ pub trait PerformanceBasedAlgorithmInputProvider {
) -> Result<BTreeMap<PrincipalId, Vec<RewardableNode>>, String>;
}

trait PerformanceBasedAlgorithm {
trait PerformanceBasedAlgorithm: AlgorithmVersion {
/// The percentile used to calculate the failure rate for a subnet.
const SUBNET_FAILURE_RATE_PERCENTILE: f64;

Expand Down Expand Up @@ -138,6 +139,7 @@ trait PerformanceBasedAlgorithm {
}

Ok(RewardsCalculatorResults {
algorithm_version: Self::VERSION,
total_rewards_xdr_permyriad,
daily_results,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ pub struct DailyResults {

#[derive(Debug, PartialEq, Eq)]
pub struct RewardsCalculatorResults {
// Algorithm version used to calculate the results.
pub algorithm_version: u32,

/// Total rewards for each provider across the entire reward period
pub total_rewards_xdr_permyriad: BTreeMap<PrincipalId, u64>,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::AlgorithmVersion;
use crate::performance_based_algorithm::results::RewardsCalculatorResults;
use crate::performance_based_algorithm::{
PerformanceBasedAlgorithm, PerformanceBasedAlgorithmInputProvider,
};
use chrono::NaiveDate;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;

// ================================================================================================
// VERSIONING SAFETY WARNING
// ================================================================================================
Expand Down Expand Up @@ -35,6 +35,10 @@ impl PerformanceBasedAlgorithm for RewardsCalculationV1 {
const MAX_REWARDS_REDUCTION: Decimal = dec!(0.8);
}

impl AlgorithmVersion for RewardsCalculationV1 {
const VERSION: u32 = 1;
}

impl RewardsCalculationV1 {
pub fn calculate_rewards(
from_date: NaiveDate,
Expand Down
Loading