diff --git a/pallets/capacity/src/lib.rs b/pallets/capacity/src/lib.rs index f1fa1146f7..d20ea92b27 100644 --- a/pallets/capacity/src/lib.rs +++ b/pallets/capacity/src/lib.rs @@ -53,7 +53,6 @@ use sp_std::ops::Mul; use frame_support::{ ensure, traits::{ - fungible::Inspect, tokens::fungible::{Inspect as InspectFungible, InspectFreeze, Mutate, MutateFreeze}, Get, Hooks, }, @@ -219,7 +218,7 @@ pub mod pallet { #[pallet::constant] type RewardPercentCap: Get; - /// The number of chunks + /// The number of chunks of Reward Pool history we expect to store #[pallet::constant] type RewardPoolChunkLength: Get; } @@ -1154,31 +1153,17 @@ impl Pallet { current_era_info.started_at + era_length.mul(era_diff.into()) - 1u32.into() } - // Find the history chunk that a given era is in and pull out the total stake for that era. + // Figure out the history chunk that a given era is in and pull out the total stake for that era. pub(crate) fn get_total_stake_for_past_era( reward_era: T::RewardEra, current_era: T::RewardEra, ) -> Result, DispatchError> { let chunk_idx: u32 = Self::get_chunk_index_for_era(reward_era, current_era) .ok_or(Error::::EraOutOfRange)?; - let mut reward_pool_chunk = Self::get_reward_pool_chunk(chunk_idx).unwrap_or_default(); // 1r - if let Some(total_for_era) = reward_pool_chunk.total_for_era(&reward_era) { - Ok(*total_for_era) - } else { - let chunks = - T::ProviderBoostHistoryLimit::get().saturating_div(T::RewardPoolChunkLength::get()); - for i in 0..chunks { - if i != chunk_idx { - reward_pool_chunk = Self::get_reward_pool_chunk(i) - .ok_or(Error::::CollectionBoundExceeded)?; - match reward_pool_chunk.total_for_era(&reward_era) { - Some(total_for_era) => return Ok(*total_for_era), - None => (), - } - } - } - Err(DispatchError::from(Error::::EraOutOfRange)) - } + let reward_pool_chunk = Self::get_reward_pool_chunk(chunk_idx).unwrap_or_default(); // 1r + let total_for_era = + reward_pool_chunk.total_for_era(&reward_era).ok_or(Error::::EraOutOfRange)?; + Ok(*total_for_era) } pub(crate) fn get_chunk_index_for_era( @@ -1200,6 +1185,11 @@ impl Pallet { (0u32..chunks).find(|&i| era_diff.le(&(chunk_len * (i + 1)).into())) } + // This is where the reward pool gets updated. + // This inserts what was the current era and total boost amount into Reward Pool history, by + // removing the oldest item in each chunk, saving it for the next chunk, then + // inserting the new item. If the entire history is full, it exits without an insert on the last chunk, + // effectively dropping the oldest item. pub(crate) fn update_provider_boost_reward_pool(era: T::RewardEra, boost_total: BalanceOf) { let mut new_era = era; let mut new_value = boost_total; @@ -1223,7 +1213,9 @@ impl Pallet { } } } else { - // since it's not full, just insert it and ignore the result. + // Since it's not full, just insert it and ignore the result. + // The only reason this is supposed to fail is if the BoundedBTree is full, and + // since we're here, this shouldn't ever fail. let _unused = chunk.try_insert(new_era, new_value); ProviderBoostRewardPools::::set(chunk_idx, Some(chunk)); break; diff --git a/pallets/capacity/src/migration/provider_boost_init.rs b/pallets/capacity/src/migration/provider_boost_init.rs index be4757bef0..6185e42d70 100644 --- a/pallets/capacity/src/migration/provider_boost_init.rs +++ b/pallets/capacity/src/migration/provider_boost_init.rs @@ -1,4 +1,7 @@ -use crate::{Config, CurrentEraInfo, RewardEraInfo}; +use crate::{ + Config, CurrentEraInfo, CurrentEraProviderBoostTotal, ProviderBoostRewardPools, RewardEraInfo, + RewardPoolHistoryChunk, +}; use frame_support::{ pallet_prelude::Weight, traits::{Get, OnRuntimeUpgrade}, @@ -16,9 +19,15 @@ impl OnRuntimeUpgrade for ProviderBoostInit { if current_era_info.eq(&RewardEraInfo::default()) { // 1r let current_block = frame_system::Pallet::::block_number(); // 1r - let era_index: T::RewardEra = 0u32.into(); + let era_index: T::RewardEra = 1u32.into(); CurrentEraInfo::::set(RewardEraInfo { era_index, started_at: current_block }); // 1w - // TODO: set up Current Reward Era total stake default value. No need for a history chunk at this point. + CurrentEraProviderBoostTotal::::set(0u32.into()); + let chunks: u32 = + T::ProviderBoostHistoryLimit::get().saturating_div(T::RewardPoolChunkLength::get()); + (0u32..chunks).for_each(|chunk_index| { + let new_chunk: RewardPoolHistoryChunk = RewardPoolHistoryChunk::new(); + ProviderBoostRewardPools::::insert(chunk_index, new_chunk); + }); T::DbWeight::get().reads_writes(2, 2) } else { T::DbWeight::get().reads(1) @@ -47,7 +56,9 @@ impl OnRuntimeUpgrade for ProviderBoostInit { let info = CurrentEraInfo::::get(); assert_eq!(info.started_at, current_block); log::info!("CurrentEraInfo.started_at is set to {:?}.", info.started_at); - assert_eq!(ProviderBoostRewardPools::::iter().count(), 1); + let chunks: u32 = + T::RewardPoolHistoryLimit::get().saturating_div(T::RewardPoolChunkLength::get()); + assert_eq!(ProviderBoostRewardPools::::iter().count(), chunks); Ok(()) } } diff --git a/pallets/capacity/src/tests/eras_tests.rs b/pallets/capacity/src/tests/eras_tests.rs index 45e199f47e..682526c762 100644 --- a/pallets/capacity/src/tests/eras_tests.rs +++ b/pallets/capacity/src/tests/eras_tests.rs @@ -6,7 +6,6 @@ use crate::{ use common_primitives::msa::MessageSourceId; use frame_support::assert_ok; use sp_core::Get; -use sp_io::storage::exists; pub fn boost_provider_and_run_to_end_of_era( staker: u64, @@ -147,6 +146,7 @@ fn get_chunk_index_for_era_works() { // assuming history limit is 12, chunk length is 3 for test in { vec![ + TestCase { era: 3, current_era: 6, expected: Some(0) }, TestCase { era: 2, current_era: 1, expected: None }, TestCase { era: 3, current_era: 16, expected: None }, TestCase { era: 1, current_era: 1, expected: None }, diff --git a/pallets/capacity/src/tests/mock.rs b/pallets/capacity/src/tests/mock.rs index 460be002fb..10f5eb9b41 100644 --- a/pallets/capacity/src/tests/mock.rs +++ b/pallets/capacity/src/tests/mock.rs @@ -1,7 +1,7 @@ use crate as pallet_capacity; use crate::{ - tests::testing_utils::set_era_and_reward_pool, BalanceOf, ProviderBoostRewardClaim, + tests::testing_utils::set_era_and_reward_pool, BalanceOf, Config, ProviderBoostRewardClaim, ProviderBoostRewardPools, ProviderBoostRewardsProvider, RewardPoolHistoryChunk, }; use common_primitives::{ @@ -15,7 +15,7 @@ use frame_support::{ use frame_system::EnsureSigned; use sp_core::{ConstU8, H256}; use sp_runtime::{ - traits::{BlakeTwo256, Convert, IdentityLookup}, + traits::{BlakeTwo256, Convert, Get, IdentityLookup}, AccountId32, BuildStorage, DispatchError, Perbill, Permill, }; use sp_std::ops::Mul; @@ -217,7 +217,9 @@ impl pallet_capacity::Config for Test { } fn initialize_reward_pool() { - for i in 0u32..5u32 { + let history_limit: u32 = ::ProviderBoostHistoryLimit::get(); + let chunks = history_limit.saturating_div(::RewardPoolChunkLength::get()); + for i in 0u32..chunks { ProviderBoostRewardPools::::insert(i, RewardPoolHistoryChunk::::new()) } } diff --git a/pallets/capacity/src/tests/reward_pool_tests.rs b/pallets/capacity/src/tests/reward_pool_tests.rs index e2e25f8c56..9640bcd09a 100644 --- a/pallets/capacity/src/tests/reward_pool_tests.rs +++ b/pallets/capacity/src/tests/reward_pool_tests.rs @@ -2,7 +2,7 @@ use crate::{ tests::{mock::*, testing_utils::set_era_and_reward_pool}, BalanceOf, Config, ProviderBoostRewardPools, RewardPoolHistoryChunk, }; -use frame_support::assert_ok; +use frame_support::{assert_ok, traits::Get}; use std::ops::Add; // Check eras_tests for how reward pool chunks are expected to be filled during @@ -86,11 +86,12 @@ fn get_total_stake_for_past_era_works_with_1_full_chunk() { new_test_ext().execute_with(|| { System::set_block_number(52); set_era_and_reward_pool(6, 51, 1000); - fill_reward_pool_history_chunk(1, 1, 3, 100); // eras 1-3 - fill_reward_pool_history_chunk(0, 4, 2, 400); // eras 4,5 - for i in 1u32..=5u32 { + fill_reward_pool_history_chunk(1, 1, 2, 100); // eras 1-3 + fill_reward_pool_history_chunk(0, 3, 3, 300); // eras 4,5 + for i in 3u32..=5u32 { let expected_total: BalanceOf = (i * 100u32).into(); - assert_eq!(Capacity::get_total_stake_for_past_era(i, 6), Ok(expected_total)); + let actual = Capacity::get_total_stake_for_past_era(i, 6); + assert_eq!(actual, Ok(expected_total)); } assert!(Capacity::get_total_stake_for_past_era(6, 6).is_err()); }) @@ -101,12 +102,12 @@ fn get_total_stake_for_past_era_works_with_2_full_chunks() { new_test_ext().execute_with(|| { System::set_block_number(72); set_era_and_reward_pool(8, 71, 1000); - fill_reward_pool_history_chunk(2, 1, 3, 100); - fill_reward_pool_history_chunk(1, 4, 3, 400); - fill_reward_pool_history_chunk(0, 7, 1, 700); + fill_reward_pool_history_chunk(2, 1, 1, 100); + fill_reward_pool_history_chunk(1, 2, 3, 200); + fill_reward_pool_history_chunk(0, 5, 3, 500); for i in 1u32..=7u32 { let expected_total: BalanceOf = (i * 100u32).into(); - assert_eq!(Capacity::get_total_stake_for_past_era(i, 9), Ok(expected_total)); + assert_eq!(Capacity::get_total_stake_for_past_era(i, 8), Ok(expected_total)); } assert!(Capacity::get_total_stake_for_past_era(8, 8).is_err()); }) @@ -116,14 +117,18 @@ fn get_total_stake_for_past_era_works_with_2_full_chunks() { fn get_total_stake_for_past_era_works_with_full_reward_pool() { new_test_ext().execute_with(|| { System::set_block_number(72); - set_era_and_reward_pool(13, 121, 1000); + let history_limit: u32 = ::ProviderBoostHistoryLimit::get(); + set_era_and_reward_pool(13, 121, (2000u32).into()); + + fill_reward_pool_history_chunk(3, 1, 3, 101); fill_reward_pool_history_chunk(2, 4, 3, 401); fill_reward_pool_history_chunk(1, 7, 3, 701); fill_reward_pool_history_chunk(0, 10, 3, 1001); - for i in 4u32..=8 { - let expected_total: BalanceOf = (i * 100u32 + 1u32).into(); - assert_eq!(Capacity::get_total_stake_for_past_era(i, 9), Ok(expected_total)); - } + + (1u32..=history_limit).for_each(|era| { + let expected_total: BalanceOf = ((era * 100u32) + 1u32).into(); + assert_eq!(Capacity::get_total_stake_for_past_era(era, 13), Ok(expected_total)); + }); assert!(Capacity::get_total_stake_for_past_era(13, 13).is_err()); }) }