From 0776e71e927145c948ea24c6dbd090ba09e97eec Mon Sep 17 00:00:00 2001 From: Eugene Kovalev Date: Fri, 25 Aug 2023 14:28:39 +0400 Subject: [PATCH 1/2] Adjust target inflation value --- pallets/staking-rewards/src/inflation.rs | 126 +++++++++++------------ pallets/staking-rewards/src/lib.rs | 23 +++-- pallets/staking-rewards/src/migration.rs | 87 ++++++++++++++-- pallets/staking-rewards/src/tests.rs | 51 +++++++++ 4 files changed, 207 insertions(+), 80 deletions(-) diff --git a/pallets/staking-rewards/src/inflation.rs b/pallets/staking-rewards/src/inflation.rs index 3e3cb7fc707..c91eacd5700 100644 --- a/pallets/staking-rewards/src/inflation.rs +++ b/pallets/staking-rewards/src/inflation.rs @@ -118,10 +118,10 @@ mod test { } static TTS: u128 = 10_000_000_000; - static STAKEABLE: u128 = 4_250_000_000; // 42.5% of TTS + static STAKEABLE: u128 = 4_849_000_000; // 48.49% of TTS static IDEAL_STAKE: Perquintill = Perquintill::from_percent(85); static MIN_INFLATION: Perquintill = Perquintill::from_percent(1); - static MAX_INFLATION: Perquintill = Perquintill::from_parts(57_800_000_000_000_000_u64); // 5.78% + static MAX_INFLATION: Perquintill = Perquintill::from_parts(60_000_000_000_000_000_u64); // 6.00% static FALLOFF: Perquintill = Perquintill::from_percent(2); static MAX_ROI: Perquintill = Perquintill::from_percent(30); static MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; @@ -136,26 +136,26 @@ mod test { let expected_payouts = vec![ (0, 100_000_000), - (63_750_000, 64_367_647), - (127_500_000, 28_735_294), - (184_352_941, 0), - (212_470_588, 0), - (240_588_235, 0), - (268_705_882, 0), - (296_823_529, 0), - (324_941_176, 0), - (353_058_824, 0), - (381_176_471, 0), - (409_294_118, 0), - (437_411_765, 0), - (465_529_412, 0), - (493_647_059, 0), - (521_764_706, 0), - (549_882_353, 0), - (578_000_000, 0), - (184_499_260, 0), - (114_937_500, 0), - (102_640_602, 0), + (72_735_000, 56_676_765), + (145_470_000, 13_353_529), + (188_235_294, 0), + (217_647_059, 0), + (247_058_824, 0), + (276_470_588, 0), + (305_882_353, 0), + (335_294_118, 0), + (364_705_882, 0), + (394_117_647, 0), + (423_529_412, 0), + (452_941_176, 0), + (482_352_941, 0), + (511_764_706, 0), + (541_176_471, 0), + (570_588_235, 0), + (600_000_000, 0), + (188_388_348, 0), + (115_625_000, 0), + (102_762_136, 0), ]; assert_eq!(staked.len(), expected_payouts.len()); @@ -188,26 +188,26 @@ mod test { let expected_payouts = vec![ (0, 273_785), - (174_538, 176_229), - (349_076, 78_673), - (504_731, 0), - (581_713, 0), - (658_695, 0), - (735_677, 0), - (812_659, 0), - (889_640, 0), - (966_622, 0), - (1_043_604, 0), - (1_120_586, 0), - (1_197_568, 0), - (1_274_550, 0), - (1_351_532, 0), - (1_428_514, 0), - (1_505_496, 0), - (1_582_478, 0), - (505_131, 0), - (314_682, 0), - (281_015, 0), + (199_138, 155_172), + (398_275, 36_560), + (515_360, 0), + (595_885, 0), + (676_410, 0), + (756_935, 0), + (837_460, 0), + (917_985, 0), + (998_510, 0), + (1_079_035, 0), + (1_159_560, 0), + (1_240_085, 0), + (1_320_610, 0), + (1_401_135, 0), + (1_481_660, 0), + (1_562_185, 0), + (1_642_710, 0), + (515_779, 0), + (316_564, 0), + (281_347, 0), ]; assert_eq!(staked.len(), expected_payouts.len()); @@ -239,27 +239,27 @@ mod test { .collect::>(); let expected_payouts = vec![ - (0, 45_631), - (29_090, 29_372), - (58_179, 13_112), - (84_122, 0), - (96_952, 0), - (109_782, 0), - (122_613, 0), - (135_443, 0), - (148_273, 0), - (161_104, 0), - (173_934, 0), - (186_764, 0), - (199_595, 0), - (212_425, 0), - (225_255, 0), - (238_086, 0), - (250_916, 0), - (263_746, 0), - (84_189, 0), - (52_447, 0), - (46_836, 0), + (0, 45_630), + (33_189, 25_862), + (66_379, 6_093), + (85_893, 0), + (99_314, 0), + (112_735, 0), + (126_155, 0), + (139_576, 0), + (152_997, 0), + (166_418, 0), + (179_839, 0), + (193_260, 0), + (206_680, 0), + (220_101, 0), + (233_522, 0), + (246_943, 0), + (260_364, 0), + (273_785, 0), + (85_963, 0), + (52_760, 0), + (46_891, 0), ]; assert_eq!(staked.len(), expected_payouts.len()); diff --git a/pallets/staking-rewards/src/lib.rs b/pallets/staking-rewards/src/lib.rs index 6bd166a94ea..0a93180a964 100644 --- a/pallets/staking-rewards/src/lib.rs +++ b/pallets/staking-rewards/src/lib.rs @@ -86,7 +86,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -367,19 +367,22 @@ impl OnUnbalanced> for Pallet { fn on_nonzero_unbalanced(minted: PositiveImbalanceOf) { let amount = minted.peek(); - let burned = T::Currency::withdraw( + if let Ok(burned) = T::Currency::withdraw( &Self::account_id(), amount, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive, - ) - .unwrap_or_else(|_| NegativeImbalanceOf::::zero()); - - // Offsetting rewards against rewards pool until the latter is not depleted. - // After that the positive imbalance is dropped adding up to the total supply. - let _ = minted.offset(burned); - - Self::deposit_event(Event::Burned { amount }); + ) { + // Offsetting rewards against rewards pool until the latter is not depleted. + // After that the positive imbalance is dropped adding up to the total supply. + let _ = minted.offset(burned); + + Self::deposit_event(Event::Burned { amount }); + } else { + log::warn!( + "Staking rewards pool has insufficient balance to burn minted rewards. The currency total supply may grow." + ); + }; } } diff --git a/pallets/staking-rewards/src/migration.rs b/pallets/staking-rewards/src/migration.rs index 32e6901fdf2..d3877bf2caa 100644 --- a/pallets/staking-rewards/src/migration.rs +++ b/pallets/staking-rewards/src/migration.rs @@ -16,14 +16,87 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{Config, Pallet, Weight}; +use crate::{pallet, Config, Pallet, Weight}; +use frame_support::traits::{Get, GetStorageVersion, OnRuntimeUpgrade}; +use sp_runtime::Perquintill; +use sp_std::marker::PhantomData; -/// Wrapper for all migrations of this pallet, based on `StorageVersion`. -pub fn migrate() -> Weight { - use frame_support::traits::GetStorageVersion; +pub struct MigrateToV2(PhantomData); - let _onchain = Pallet::::on_chain_storage_version(); - let weight: Weight = Weight::zero(); +impl OnRuntimeUpgrade for MigrateToV2 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); - weight + log::info!( + "🚚 Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + let mut weight = T::DbWeight::get().reads(1); // 1 read for on chain storage version. + + if current == 2 && onchain == 1 { + // Adjusted target inflation parameter: 6.00% + let adjusted_inflation: Perquintill = Perquintill::from_percent(6); + pallet::TargetInflation::::put(adjusted_inflation); + + current.put::>(); + + log::info!("Successfully migrated storage from v1 to v2"); + + // 1 write for `TargetInflation` + weight += T::DbWeight::get().writes(1) + } else { + log::info!("❌ Migration did not execute. This probably should be removed"); + } + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + use parity_scale_codec::Encode; + + let inflation = pallet::TargetInflation::::get(); + assert_eq!(inflation, Perquintill::from_rational(578_u64, 10_000_u64)); + Ok(inflation.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + use parity_scale_codec::Decode; + + let inflation: Perquintill = Decode::decode(&mut &state[..]).unwrap(); + assert_eq!(inflation, Perquintill::from_percent(6),); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::*; + use frame_support::traits::StorageVersion; + + #[test] + fn migrate_to_v2() { + ExtBuilder::default() + .initial_authorities(vec![(VAL_1_STASH, VAL_1_CONTROLLER, VAL_1_AUTH_ID)]) + .stash(VALIDATOR_STAKE) + .endowment(ENDOWMENT) + .target_inflation(Perquintill::from_rational(578_u64, 10_000_u64)) + .build() + .execute_with(|| { + StorageVersion::new(1).put::>(); + + let weight = MigrateToV2::::on_runtime_upgrade(); + assert_ne!(weight.ref_time(), 0); + + assert_eq!( + pallet::TargetInflation::::get(), + Perquintill::from_percent(6), + ); + }) + } } diff --git a/pallets/staking-rewards/src/tests.rs b/pallets/staking-rewards/src/tests.rs index 74ba782673e..e1f1a230ff7 100644 --- a/pallets/staking-rewards/src/tests.rs +++ b/pallets/staking-rewards/src/tests.rs @@ -1183,6 +1183,57 @@ fn unclaimed_rewards_burn() { }); } +#[test] +fn empty_rewards_pool_causes_inflation() { + let (target_inflation, ideal_stake, _, non_stakeable) = sensible_defaults(); + let pool_balance = 0; // empty rewards pool + let mut ext = with_parameters(target_inflation, ideal_stake, pool_balance, non_stakeable); + ext.execute_with(|| { + // Getting up-to-date data on era duration (they may differ from runtime constants) + let sessions_per_era = ::SessionsPerEra::get() as u64; + let epoch_duration = SESSION_DURATION; + let era_duration = sessions_per_era * epoch_duration; + + let (initial_total_issuance, _, _, initial_rewards_pool_balance) = chain_state(); + assert_eq!(initial_rewards_pool_balance, 0); // ED is auto-deducted by the getter function + + // Running chain until era rollover + run_to_block(era_duration + 1); + + // No payout is expected for era #0 anyway because the "official" staked amount is 0 + assert_eq!( + Staking::eras_validator_reward(0) + .expect("ErasValidatorReward storage must exist after era end; qed"), + 0 + ); + + // Running chain until the next era rollover + run_to_block(2 * era_duration + 1); + + // Claim rewards to trigger rewards minting + for era in 0_u32..2 { + pallet_staking::Validators::::iter().for_each(|(stash_id, _)| { + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(SIGNER), + stash_id, + era + )); + }); + } + + // Take up-to-date measurements of the chain stats + let (total_issuance, _, _, rewards_pool_balance) = chain_state(); + + // The rewards pool balance is still 0: we should have failed to offset any rewards + assert_eq!(initial_rewards_pool_balance, rewards_pool_balance); + // Staker rewards for eras 0 and 1 + let actual_rewards = Staking::eras_validator_reward(1) + .expect("ErasValidatorReward storage must exist after era end; qed"); + // Total issuance grew accordingly have changed + assert_eq!(total_issuance, initial_total_issuance + actual_rewards); + }); +} + fn sensible_defaults() -> (Perquintill, Perquintill, u128, Perquintill) { ( Perquintill::from_rational(578_u64, 10_000_u64), From 9293f4bc48796254989ff8c7c68fc4180eb982b4 Mon Sep 17 00:00:00 2001 From: Eugene Kovalev Date: Sun, 27 Aug 2023 17:56:35 +0300 Subject: [PATCH 2/2] Correct runtime upgrade test --- pallets/staking-rewards/src/migration.rs | 17 ++++++++++++----- pallets/staking-rewards/src/mock.rs | 5 ----- runtime/vara/src/migrations.rs | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pallets/staking-rewards/src/migration.rs b/pallets/staking-rewards/src/migration.rs index d3877bf2caa..28933c1380c 100644 --- a/pallets/staking-rewards/src/migration.rs +++ b/pallets/staking-rewards/src/migration.rs @@ -20,6 +20,8 @@ use crate::{pallet, Config, Pallet, Weight}; use frame_support::traits::{Get, GetStorageVersion, OnRuntimeUpgrade}; use sp_runtime::Perquintill; use sp_std::marker::PhantomData; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; pub struct MigrateToV2(PhantomData); @@ -45,8 +47,8 @@ impl OnRuntimeUpgrade for MigrateToV2 { log::info!("Successfully migrated storage from v1 to v2"); - // 1 write for `TargetInflation` - weight += T::DbWeight::get().writes(1) + // 1 write for `TargetInflation` + 1 write for `StorageVersion` + weight += T::DbWeight::get().writes(2) } else { log::info!("❌ Migration did not execute. This probably should be removed"); } @@ -67,8 +69,10 @@ impl OnRuntimeUpgrade for MigrateToV2 { fn post_upgrade(state: Vec) -> Result<(), &'static str> { use parity_scale_codec::Decode; - let inflation: Perquintill = Decode::decode(&mut &state[..]).unwrap(); - assert_eq!(inflation, Perquintill::from_percent(6),); + let old_inflation: Perquintill = Decode::decode(&mut &state[..]).unwrap(); + let new_inflation = pallet::TargetInflation::::get(); + assert_ne!(old_inflation, new_inflation); + assert_eq!(new_inflation, Perquintill::from_percent(6)); Ok(()) } } @@ -91,7 +95,10 @@ mod tests { StorageVersion::new(1).put::>(); let weight = MigrateToV2::::on_runtime_upgrade(); - assert_ne!(weight.ref_time(), 0); + assert_eq!( + weight, + ::DbWeight::get().reads_writes(1, 2) + ); assert_eq!( pallet::TargetInflation::::get(), diff --git a/pallets/staking-rewards/src/mock.rs b/pallets/staking-rewards/src/mock.rs index d257504f23c..d491261680b 100644 --- a/pallets/staking-rewards/src/mock.rs +++ b/pallets/staking-rewards/src/mock.rs @@ -612,20 +612,15 @@ pub(crate) fn run_for_n_blocks(n: u64) { // Run on_initialize hooks in order as they appear in AllPalletsWithSystem. pub(crate) fn on_initialize(new_block_number: BlockNumberFor) { - System::on_initialize(new_block_number); Timestamp::set_timestamp(new_block_number.saturating_mul(MILLISECS_PER_BLOCK)); - Balances::on_initialize(new_block_number); Authorship::on_initialize(new_block_number); Session::on_initialize(new_block_number); - Staking::on_initialize(new_block_number); } // Run on_finalize hooks (in pallets reverse order, as they appear in AllPalletsWithSystem) pub(crate) fn on_finalize(current_blk: BlockNumberFor) { Staking::on_finalize(current_blk); Authorship::on_finalize(current_blk); - Balances::on_finalize(current_blk); - System::on_finalize(current_blk); } pub fn default_test_ext() -> sp_io::TestExternalities { diff --git a/runtime/vara/src/migrations.rs b/runtime/vara/src/migrations.rs index 70cb9d3171e..cf92a300c39 100644 --- a/runtime/vara/src/migrations.rs +++ b/runtime/vara/src/migrations.rs @@ -5,4 +5,5 @@ pub type Migrations = ( pallet_gear_scheduler::migration::MigrateToV2, pallet_gear_gas::migrations::v2::MigrateToV2, pallet_gear_messenger::migrations::MigrateToV2, + pallet_gear_staking_rewards::migration::MigrateToV2, );