From 0fd6bafe7f0053071ecbe310f7e5adac0cdef55b Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 8 Jan 2024 14:27:44 +0100 Subject: [PATCH 01/16] Fix for incorrect add stake --- .../dapp-staking-v3/src/test/testing_utils.rs | 60 +++++++++++--- .../dapp-staking-v3/src/test/tests_types.rs | 81 ++++++++++++++++++- pallets/dapp-staking-v3/src/types.rs | 41 +++++----- 3 files changed, 147 insertions(+), 35 deletions(-) diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index ea1dfd18f..37a029390 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -467,20 +467,44 @@ pub(crate) fn assert_stake( let post_staker_info = post_snapshot .staker_info .get(&(account, *smart_contract)) - .expect("Entry must exist since 'stake' operation was successfull."); + .expect("Entry must exist since 'stake' operation was successful."); let post_contract_stake = post_snapshot .contract_stake .get(&pre_snapshot.integrated_dapps[&smart_contract].id) - .expect("Entry must exist since 'stake' operation was successfull."); + .expect("Entry must exist since 'stake' operation was successful."); let post_era_info = post_snapshot.current_era_info; // 1. verify ledger // ===================== // ===================== - assert_eq!( - post_ledger.staked, pre_ledger.staked, - "Must remain exactly the same." - ); + if is_account_ledger_expired(pre_ledger, stake_period) { + assert!(post_ledger.staked.is_empty()); + } else { + match pre_ledger.staked_future { + Some(stake_amount) => { + if stake_amount.era == pre_snapshot.active_protocol_state.era { + assert_eq!( + post_ledger.staked, stake_amount, + "Future entry must be moved over to the current entry." + ); + } else if stake_amount.era == pre_snapshot.active_protocol_state.era + 1 { + assert_eq!( + post_ledger.staked, pre_ledger.staked, + "Must remain exactly the same, only future must be updated." + ); + } else { + panic!("Invalid future entry era."); + } + } + None => { + assert_eq!( + post_ledger.staked, pre_ledger.staked, + "Must remain exactly the same since there's nothing to be moved." + ); + } + } + } + assert_eq!(post_ledger.staked_future.unwrap().period, stake_period); assert_eq!( post_ledger.staked_amount(stake_period), @@ -625,7 +649,7 @@ pub(crate) fn assert_unstake( let post_contract_stake = post_snapshot .contract_stake .get(&pre_snapshot.integrated_dapps[&smart_contract].id) - .expect("Entry must exist since 'unstake' operation was successfull."); + .expect("Entry must exist since 'unstake' operation was successful."); let post_era_info = post_snapshot.current_era_info; // 1. verify ledger @@ -652,9 +676,11 @@ pub(crate) fn assert_unstake( ); } else { let post_staker_info = post_snapshot - .staker_info - .get(&(account, *smart_contract)) - .expect("Entry must exist since 'stake' operation was successfull and it wasn't a full unstake."); + .staker_info + .get(&(account, *smart_contract)) + .expect( + "Entry must exist since 'stake' operation was successful and it wasn't a full unstake.", + ); assert_eq!(post_staker_info.period_number(), unstake_period); assert_eq!( post_staker_info.total_staked_amount(), @@ -989,7 +1015,7 @@ pub(crate) fn assert_claim_dapp_reward( assert_eq!( pre_reward_info.dapps.len(), post_reward_info.dapps.len() + 1, - "Entry must have been removed after successfull reward claim." + "Entry must have been removed after successful reward claim." ); } @@ -1463,3 +1489,15 @@ pub(crate) fn required_number_of_reward_claims(account: AccountId) -> u32 { second - first + 1 } + +// TODO +pub(crate) fn is_account_ledger_expired( + ledger: &AccountLedgerFor, + current_period: PeriodNumber, +) -> bool { + let valid_threshold_period = DappStaking::oldest_claimable_period(current_period); + match ledger.staked_period() { + Some(staked_period) if staked_period < valid_threshold_period => true, + _ => false, + } +} diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 61c1740b5..5dc3eea11 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -507,7 +507,7 @@ fn account_ledger_staked_era_period_works() { } #[test] -fn account_ledger_add_stake_amount_basic_example_works() { +fn account_ledger_add_stake_amount_basic_example_with_different_subperiods_works() { get_u32_type!(UnlockingDummy, 5); let mut acc_ledger = AccountLedger::::default(); @@ -554,6 +554,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { .period, period_1 ); + assert_eq!(acc_ledger.staked_future.unwrap().era, era_1 + 1); assert_eq!(acc_ledger.staked_future.unwrap().voting, stake_amount); assert!(acc_ledger.staked_future.unwrap().build_and_earn.is_zero()); assert_eq!(acc_ledger.staked_amount(period_1), stake_amount); @@ -566,7 +567,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { .is_zero()); // Second scenario - stake some more, but to the next period type - let snapshot = acc_ledger.staked; + let snapshot = acc_ledger.staked_future.unwrap(); let period_info_2 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, @@ -583,6 +584,82 @@ fn account_ledger_add_stake_amount_basic_example_works() { acc_ledger.staked_amount_for_type(Subperiod::BuildAndEarn, period_1), 1 ); + + assert_eq!(acc_ledger.staked_future.unwrap().era, era_2 + 1); + assert_eq!(acc_ledger.staked_future.unwrap().voting, stake_amount); + assert_eq!(acc_ledger.staked_future.unwrap().build_and_earn, 1); + + assert_eq!(acc_ledger.staked, snapshot); +} + +#[test] +fn account_ledger_add_stake_amount_basic_example_with_same_subperiods_works() { + get_u32_type!(UnlockingDummy, 5); + let mut acc_ledger = AccountLedger::::default(); + + // 1st scenario - stake some amount in first era of the `Build&Earn` subperiod, and ensure values are as expected. + let era_1 = 2; + let period_1 = 1; + let period_info = PeriodInfo { + number: period_1, + subperiod: Subperiod::BuildAndEarn, + next_subperiod_start_era: 100, + }; + let lock_amount = 17; + let stake_amount = 11; + acc_ledger.add_lock_amount(lock_amount); + + assert!(acc_ledger + .add_stake_amount(stake_amount, era_1, period_info) + .is_ok()); + + assert!( + acc_ledger.staked.is_empty(), + "Current era must remain unchanged." + ); + assert_eq!(acc_ledger.staked_future.unwrap().period, period_1); + assert_eq!(acc_ledger.staked_future.unwrap().era, era_1 + 1); + assert_eq!( + acc_ledger.staked_future.unwrap().build_and_earn, + stake_amount + ); + assert!(acc_ledger.staked_future.unwrap().voting.is_zero()); + assert_eq!(acc_ledger.staked_amount(period_1), stake_amount); + assert_eq!( + acc_ledger.staked_amount_for_type(Subperiod::BuildAndEarn, period_1), + stake_amount + ); + assert!(acc_ledger + .staked_amount_for_type(Subperiod::Voting, period_1) + .is_zero()); + + // 2nd scenario - stake again, in the same era + let snapshot = acc_ledger.staked; + assert!(acc_ledger.add_stake_amount(1, era_1, period_info).is_ok()); + assert_eq!(acc_ledger.staked, snapshot); + assert_eq!(acc_ledger.staked_amount(period_1), stake_amount + 1); + + // 2nd scenario - advance an era, and stake some more + let snapshot = acc_ledger.staked_future.unwrap(); + let era_2 = era_1 + 1; + assert!(acc_ledger.add_stake_amount(1, era_2, period_info).is_ok()); + + assert_eq!(acc_ledger.staked_amount(period_1), stake_amount + 2); + assert!(acc_ledger + .staked_amount_for_type(Subperiod::Voting, period_1) + .is_zero(),); + assert_eq!( + acc_ledger.staked_amount_for_type(Subperiod::BuildAndEarn, period_1), + stake_amount + 2 + ); + assert_eq!(acc_ledger.staked_future.unwrap().period, period_1); + assert_eq!(acc_ledger.staked_future.unwrap().era, era_2 + 1); + assert_eq!( + acc_ledger.staked_future.unwrap().build_and_earn, + stake_amount + 2 + ); + assert!(acc_ledger.staked_future.unwrap().voting.is_zero()); + assert_eq!(acc_ledger.staked, snapshot); } diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 671f5a0e9..06dedb027 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -114,8 +114,6 @@ pub enum AccountLedgerError { UnstakeAmountLargerThanStake, /// Nothing to claim. NothingToClaim, - /// Rewards have already been claimed - AlreadyClaimed, /// Attempt to crate the iterator failed due to incorrect data. InvalidIterator, } @@ -123,7 +121,7 @@ pub enum AccountLedgerError { /// Distinct subperiods in dApp staking protocol. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] pub enum Subperiod { - /// Subperiod during which the focus is on voting. + /// Subperiod during which the focus is on voting. No rewards are earned during this subperiod. Voting, /// Subperiod during which dApps and stakers earn rewards. BuildAndEarn, @@ -160,7 +158,7 @@ impl PeriodInfo { } } -/// Information describing relevant information for a finished period. +/// Struct with relevant information for a finished period. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] pub struct PeriodEndInfo { /// Bonus reward pool allocated for 'loyal' stakers @@ -241,10 +239,9 @@ impl ProtocolState { next_subperiod_start_era: EraNumber, next_era_start: BlockNumber, ) { - let period_number = if self.subperiod() == Subperiod::BuildAndEarn { - self.period_number().saturating_add(1) - } else { - self.period_number() + let period_number = match self.subperiod() { + Subperiod::Voting => self.period_number(), + Subperiod::BuildAndEarn => self.period_number().saturating_add(1), }; self.period_info = PeriodInfo { @@ -261,11 +258,11 @@ impl ProtocolState { pub enum DAppState { /// dApp is registered and active. Registered, - /// dApp has been unregistered in the contained era + /// dApp has been unregistered in the contained era. Unregistered(#[codec(compact)] EraNumber), } -/// General information about dApp. +/// General information about a dApp. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] pub struct DAppInfo { /// Owner of the dApp, default reward beneficiary. @@ -295,7 +292,7 @@ impl DAppInfo { } /// How much was unlocked in some block. -#[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] +#[derive(Encode, Decode, MaxEncodedLen, Clone, Default, Copy, Debug, PartialEq, Eq, TypeInfo)] pub struct UnlockingChunk { /// Amount undergoing the unlocking period. #[codec(compact)] @@ -305,15 +302,6 @@ pub struct UnlockingChunk { pub unlock_block: BlockNumber, } -impl Default for UnlockingChunk { - fn default() -> Self { - Self { - amount: Balance::zero(), - unlock_block: BlockNumber::zero(), - } - } -} - /// General info about an account's lock & stakes. /// /// ## Overview @@ -535,7 +523,7 @@ where .saturating_sub(self.staked_amount(active_period)) } - /// Amount that is staked, in respect to currently active period. + /// Amount that is staked, in respect to the currently active period. pub fn staked_amount(&self, active_period: PeriodNumber) -> Balance { // First check the 'future' entry, afterwards check the 'first' entry match self.staked_future { @@ -569,13 +557,16 @@ where ) -> Result<(), AccountLedgerError> { if !self.staked.is_empty() { // In case entry for the current era exists, it must match the era exactly. + // No other scenario is possible since stake/unstake is not allowed without claiming rewards first. if self.staked.era != current_era { return Err(AccountLedgerError::InvalidEra); } if self.staked.period != current_period_info.number { return Err(AccountLedgerError::InvalidPeriod); } - // In case it doesn't (i.e. first time staking), then the future era must either be the current or the next era. + // In case only the 'future' entry exists, then the future era must either be the current or the next era. + // 'Next era' covers the simple scenario where stake is only valid from the next era. + // 'Current era' covers the scenario where stake was made in previous era, and we've moved to the next era. } else if let Some(stake_amount) = self.staked_future { if stake_amount.era != current_era.saturating_add(1) && stake_amount.era != current_era { @@ -618,7 +609,13 @@ where // Update existing entry if it exists, otherwise create it. match self.staked_future.as_mut() { Some(stake_amount) => { + // In case future entry exists, check if it should be moved over to the 'current' entry. + if stake_amount.era == current_era { + self.staked = *stake_amount; + } + stake_amount.add(amount, current_period_info.subperiod); + stake_amount.era = current_era.saturating_add(1); } None => { let mut stake_amount = self.staked; From f0b90611d5c1ce6158de86d10246fe62f318a860 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 8 Jan 2024 14:34:44 +0100 Subject: [PATCH 02/16] Minor adjustments --- pallets/dapp-staking-v3/src/test/testing_utils.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 37a029390..8eadc3e66 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -478,7 +478,10 @@ pub(crate) fn assert_stake( // ===================== // ===================== if is_account_ledger_expired(pre_ledger, stake_period) { - assert!(post_ledger.staked.is_empty()); + assert!( + post_ledger.staked.is_empty(), + "Must be cleaned up if expired." + ); } else { match pre_ledger.staked_future { Some(stake_amount) => { @@ -506,6 +509,7 @@ pub(crate) fn assert_stake( } assert_eq!(post_ledger.staked_future.unwrap().period, stake_period); + assert_eq!(post_ledger.staked_future.unwrap().era, stake_era); assert_eq!( post_ledger.staked_amount(stake_period), pre_ledger.staked_amount(stake_period) + amount, @@ -1490,7 +1494,9 @@ pub(crate) fn required_number_of_reward_claims(account: AccountId) -> u32 { second - first + 1 } -// TODO +/// Check whether the given account ledger's stake rewards have expired. +/// +/// `true` if expired, `false` otherwise. pub(crate) fn is_account_ledger_expired( ledger: &AccountLedgerFor, current_period: PeriodNumber, From 47400384f54ec6312bc1242ebc89baf80811635a Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 8 Jan 2024 15:51:16 +0100 Subject: [PATCH 03/16] Adjustments --- pallets/dapp-staking-v3/src/lib.rs | 6 +- pallets/dapp-staking-v3/src/types.rs | 42 +- precompiles/dapp-staking-v3/src/test/mod.rs | 2 +- .../dapp-staking-v3/src/test/tests_v1.rs | 867 ------------------ .../dapp-staking-v3/src/test/tests_v2.rs | 777 +++++++++++----- .../dapp-staking-v3/src/test/tests_v3.rs | 526 +++++++++++ 6 files changed, 1110 insertions(+), 1110 deletions(-) delete mode 100644 precompiles/dapp-staking-v3/src/test/tests_v1.rs create mode 100644 precompiles/dapp-staking-v3/src/test/tests_v3.rs diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index f45abf32e..9b23375d3 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -19,7 +19,7 @@ //! # dApp Staking v3 Pallet //! //! For detailed high level documentation, please refer to the attached README.md file. -//! The crate level docs will cover overal pallet structure & implementation details. +//! The crate level docs will cover overall pallet structure & implementation details. //! //! ## Overview //! @@ -27,9 +27,9 @@ //! It covers everything from locking, staking, tier configuration & assignment, reward calculation & payout. //! //! The `types` module contains all of the types used to implement the pallet. -//! All of these _types_ are exentisvely tested in their dedicated `test_types` module. +//! All of these _types_ are extensively tested in their dedicated `test_types` module. //! -//! Rest of the pallet logic is concenrated in the lib.rs file. +//! Rest of the pallet logic is concentrated in the lib.rs file. //! This logic is tested in the `tests` module, with the help of extensive `testing_utils`. //! diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 06dedb027..bb9e48469 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -164,7 +164,7 @@ pub struct PeriodEndInfo { /// Bonus reward pool allocated for 'loyal' stakers #[codec(compact)] pub bonus_reward_pool: Balance, - /// Total amount staked (remaining) from the voting period. + /// Total amount staked (remaining) from the voting subperiod. #[codec(compact)] pub total_vp_stake: Balance, /// Final era, inclusive, in which the period ended. @@ -768,7 +768,7 @@ where /// Helper internal struct for iterating over `(era, stake amount)` pairs. /// -/// Due to how `AccountLedger` is implemented, few scenarios are possible when claming rewards: +/// Due to how `AccountLedger` is implemented, few scenarios are possible when claiming rewards: /// /// 1. `staked` has some amount, `staked_future` is `None` /// * `maybe_first` is `None`, span describes the entire range @@ -782,7 +782,7 @@ pub struct EraStakePairIter { maybe_first: Option<(EraNumber, Balance)>, /// Starting era of the span. start_era: EraNumber, - /// Ending era of the span. + /// Ending era of the span, inclusive. end_era: EraNumber, /// Staked amount in the span. amount: Balance, @@ -838,10 +838,10 @@ impl Iterator for EraStakePairIter { /// Describes stake amount in an particular era/period. #[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] pub struct StakeAmount { - /// Amount of staked funds accounting for the voting period. + /// Amount of staked funds accounting for the voting subperiod. #[codec(compact)] pub voting: Balance, - /// Amount of staked funds accounting for the build&earn period. + /// Amount of staked funds accounting for the build&earn subperiod. #[codec(compact)] pub build_and_earn: Balance, /// Era to which this stake amount refers to. @@ -881,10 +881,10 @@ impl StakeAmount { /// Unstake the specified `amount` for the specified `subperiod`. /// - /// In case subperiod is `Voting`, the amount is subtracted from the voting period. + /// In case subperiod is `Voting`, the amount is subtracted from the voting subperiod. /// /// In case subperiod is `Build&Earn`, the amount is first subtracted from the - /// build&earn amount, and any rollover is subtracted from the voting period. + /// build&earn amount, and any rollover is subtracted from the voting subperiod. pub fn subtract(&mut self, amount: Balance, subperiod: Subperiod) { match subperiod { Subperiod::Voting => self.voting.saturating_reduce(amount), @@ -906,7 +906,7 @@ impl StakeAmount { } } -/// Info about current era, including the rewards, how much is locked, unlocking, etc. +/// Info about an era, including the rewards, how much is locked, unlocking, etc. #[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] pub struct EraInfo { /// How much balance is locked in dApp staking. @@ -966,7 +966,7 @@ impl EraInfo { self.next_stake_amount.total() } - /// Staked amount of specifeid `type` in the next era. + /// Staked amount of specified `type` in the next era. pub fn staked_amount_next_era(&self, subperiod: Subperiod) -> Balance { self.next_stake_amount.for_type(subperiod) } @@ -977,7 +977,7 @@ impl EraInfo { /// `next_subperiod` - `None` if no subperiod change, `Some(type)` if `type` is starting from the next era. pub fn migrate_to_next_era(&mut self, next_subperiod: Option) { match next_subperiod { - // If next era marks start of new voting period period, it means we're entering a new period + // If next era marks start of new voting subperiod period, it means we're entering a new period Some(Subperiod::Voting) => { for stake_amount in [&mut self.current_stake_amount, &mut self.next_stake_amount] { stake_amount.voting = Zero::zero(); @@ -996,7 +996,7 @@ impl EraInfo { /// Information about how much a particular staker staked on a particular smart contract. /// -/// Keeps track of amount staked in the 'voting period', as well as 'build&earn period'. +/// Keeps track of amount staked in the 'voting subperiod', as well as 'build&earn subperiod'. #[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] pub struct SingularStakingInfo { /// Staked amount @@ -1020,7 +1020,7 @@ impl SingularStakingInfo { era: 0, period, }, - // Loyalty staking is only possible if stake is first made during the voting period. + // Loyalty staking is only possible if stake is first made during the voting subperiod. loyal_staker: subperiod == Subperiod::Voting, } } @@ -1034,10 +1034,10 @@ impl SingularStakingInfo { /// Unstakes some of the specified amount from the contract. /// - /// In case the `amount` being unstaked is larger than the amount staked in the `voting period`, - /// and `voting period` has passed, this will remove the _loyalty_ flag from the staker. + /// In case the `amount` being unstaked is larger than the amount staked in the `Voting` subperiod, + /// and `Voting` subperiod has passed, this will remove the _loyalty_ flag from the staker. /// - /// Returns the amount that was unstaked from the `voting period` stake, and from the `build&earn period` stake. + /// Returns the amount that was unstaked from the `Voting` subperiod stake, and from the `Build&Earn` subperiod stake. pub fn unstake( &mut self, amount: Balance, @@ -1073,7 +1073,7 @@ impl SingularStakingInfo { self.staked.for_type(subperiod) } - /// If `true` staker has staked during voting period and has never reduced their sta + /// If `true` staker has staked during voting subperiod and has never reduced their sta pub fn is_loyal(&self) -> bool { self.loyal_staker } @@ -1191,7 +1191,7 @@ impl ContractStakeAmount { stake_amount.add(amount, period_info.subperiod); return; } - // Future entry has older era, but periods match so overwrite the 'current' entry with it + // Future entry has an older era, but periods match so overwrite the 'current' entry with it Some(stake_amount) if stake_amount.period == period_info.number => { self.staked = *stake_amount; } @@ -1244,7 +1244,7 @@ impl ContractStakeAmount { stake_amount.subtract(amount, period_info.subperiod); } - // Conevnience cleanup + // Convenience cleanup if self.staked.is_empty() { self.staked = Default::default(); } @@ -1335,7 +1335,7 @@ where } /// Push new `EraReward` entry into the span. - /// If span is non-empty, the provided `era` must be exactly one era after the last one in the span. + /// If span is not empty, the provided `era` must be exactly one era after the last one in the span. pub fn push( &mut self, era: EraNumber, @@ -1531,7 +1531,7 @@ impl> TiersConfiguration { pub fn is_valid(&self) -> bool { let number_of_tiers: usize = NT::get() as usize; number_of_tiers == self.slots_per_tier.len() - // All vecs length must match number of tiers. + // All vector length must match number of tiers. && number_of_tiers == self.reward_portion.len() && number_of_tiers == self.tier_thresholds.len() // Total number of slots must match the sum of slots per tier. @@ -1712,7 +1712,7 @@ impl, NT: Get> DAppTierRewards { pub enum DAppTierError { /// Specified dApp Id doesn't exist in any tier. NoDAppInTiers, - /// Internal, unexpected error occured. + /// Internal, unexpected error occurred. InternalError, } diff --git a/precompiles/dapp-staking-v3/src/test/mod.rs b/precompiles/dapp-staking-v3/src/test/mod.rs index a33eb2295..5bc195b3c 100644 --- a/precompiles/dapp-staking-v3/src/test/mod.rs +++ b/precompiles/dapp-staking-v3/src/test/mod.rs @@ -17,6 +17,6 @@ // along with Astar. If not, see . mod mock; -mod tests_v1; mod tests_v2; +mod tests_v3; mod types; diff --git a/precompiles/dapp-staking-v3/src/test/tests_v1.rs b/precompiles/dapp-staking-v3/src/test/tests_v1.rs deleted file mode 100644 index 8d93b5619..000000000 --- a/precompiles/dapp-staking-v3/src/test/tests_v1.rs +++ /dev/null @@ -1,867 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later - -// Astar is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Astar is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Astar. If not, see . - -extern crate alloc; -use crate::{test::mock::*, *}; -use frame_support::assert_ok; -use frame_system::RawOrigin; -use precompile_utils::testing::*; -use sp_core::H160; -use sp_runtime::traits::Zero; - -use assert_matches::assert_matches; - -use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber, EraRewards}; - -#[test] -fn read_current_era_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - precompiles() - .prepare_test( - Alice, - precompile_address(), - PrecompileCall::read_current_era {}, - ) - .expect_no_logs() - .execute_returns(ActiveProtocolState::::get().era); - - // advance a few eras, check value again - advance_to_era(7); - precompiles() - .prepare_test( - Alice, - precompile_address(), - PrecompileCall::read_current_era {}, - ) - .expect_no_logs() - .execute_returns(ActiveProtocolState::::get().era); - }); -} - -#[test] -fn read_unbonding_period_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - let unlocking_period_in_eras: EraNumber = - ::UnlockingPeriod::get(); - - precompiles() - .prepare_test( - Alice, - precompile_address(), - PrecompileCall::read_unbonding_period {}, - ) - .expect_no_logs() - .execute_returns(unlocking_period_in_eras); - }); -} - -#[test] -fn read_era_reward_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Check historic era for rewards - let era = 3; - advance_to_era(era + 1); - - let span_index = DAppStaking::::era_reward_span_index(era); - - let era_rewards_span = EraRewards::::get(span_index).expect("Entry must exist."); - let expected_reward = era_rewards_span - .get(era) - .map(|r| r.staker_reward_pool + r.dapp_reward_pool) - .expect("It's history era so it must exist."); - assert!(expected_reward > 0, "Sanity check."); - - precompiles() - .prepare_test( - Alice, - precompile_address(), - PrecompileCall::read_era_reward { era }, - ) - .expect_no_logs() - .execute_returns(expected_reward); - - // Check current era for rewards, must be zero - precompiles() - .prepare_test( - Alice, - precompile_address(), - PrecompileCall::read_era_reward { era: era + 1 }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - }); -} - -#[test] -fn read_era_staked_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - let anchor_era = ActiveProtocolState::::get().era; - - // 1. Current era stake must be zero, since stake is only valid from the next era. - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_era_staked { era: anchor_era }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_era_staked { - era: anchor_era + 1, - }, - ) - .expect_no_logs() - .execute_returns(amount); - - // 2. Advance to next era, and check next era after the anchor. - advance_to_era(anchor_era + 5); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_era_staked { - era: anchor_era + 1, - }, - ) - .expect_no_logs() - .execute_returns(amount); - - // 3. Check era after the next one, must throw an error. - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_era_staked { - era: ActiveProtocolState::::get().era + 2, - }, - ) - .expect_no_logs() - .execute_reverts(|output| output == b"Era is in the future"); - }); -} - -#[test] -fn read_staked_amount_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - let staker_h160 = ALICE; - let dynamic_addresses = into_dynamic_addresses(staker_h160); - - // 1. Sanity checks - must be zero before anything is staked. - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount { - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - } - - // 2. Stake some amount and check again - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount { - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(amount); - } - - // 3. Advance into next period, it should be reset back to zero - advance_to_next_period(); - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount { - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - } - }); -} - -#[test] -fn read_staked_amount_on_contract_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let dynamic_addresses = into_dynamic_addresses(staker_h160); - - // 1. Sanity checks - must be zero before anything is staked. - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount_on_contract { - contract_h160: smart_contract_address.into(), - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - } - - // 2. Stake some amount and check again - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount_on_contract { - contract_h160: smart_contract_address.into(), - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(amount); - } - - // 3. Advance into next period, it should be reset back to zero - advance_to_next_period(); - for staker in &dynamic_addresses { - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_staked_amount_on_contract { - contract_h160: smart_contract_address.into(), - staker: staker.clone(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - } - }); -} - -#[test] -fn read_contract_stake_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - - // 1. Sanity checks - must be zero before anything is staked. - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_contract_stake { - contract_h160: smart_contract_address.into(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - - // 2. Stake some amount and check again - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_contract_stake { - contract_h160: smart_contract_address.into(), - }, - ) - .expect_no_logs() - .execute_returns(amount); - - // 3. Advance into next period, it should be reset back to zero - advance_to_next_period(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::read_contract_stake { - contract_h160: smart_contract_address.into(), - }, - ) - .expect_no_logs() - .execute_returns(Balance::zero()); - }); -} - -#[test] -fn register_is_unsupported() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - precompiles() - .prepare_test( - ALICE, - precompile_address(), - PrecompileCall::register { - _address: Default::default(), - }, - ) - .expect_no_logs() - .execute_reverts(|output| output == b"register via evm precompile is not allowed"); - }); -} - -#[test] -fn set_reward_destination_is_unsupported() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - precompiles() - .prepare_test( - ALICE, - precompile_address(), - PrecompileCall::set_reward_destination { _destination: 0 }, - ) - .expect_no_logs() - .execute_reverts(|output| { - output == b"Setting reward destination is no longer supported." - }); - }); -} - -#[test] -fn bond_and_stake_with_two_calls_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - assert_ok!(DappStaking::register( - RawOrigin::Root.into(), - AddressMapper::into_account_id(staker_h160), - smart_contract.clone() - )); - - // Lock some amount, but not enough to cover the `bond_and_stake` call. - let pre_lock_amount = 500; - let stake_amount = 1_000_000; - assert_ok!(DappStaking::lock( - RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), - pre_lock_amount, - )); - - // Execute legacy call, expect missing funds to be locked. - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::bond_and_stake { - contract_h160: smart_contract_address.into(), - amount: stake_amount, - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 2); - let additional_lock_amount = stake_amount - pre_lock_amount; - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Locked { - amount, - .. - } if amount == additional_lock_amount - ); - assert_matches!( - events[1].clone(), - pallet_dapp_staking_v3::Event::Stake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract && amount == stake_amount - ); - }); -} - -#[test] -fn bond_and_stake_with_single_call_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - assert_ok!(DappStaking::register( - RawOrigin::Root.into(), - AddressMapper::into_account_id(staker_h160), - smart_contract.clone() - )); - - // Lock enough amount to cover `bond_and_stake` call. - let amount = 3000; - assert_ok!(DappStaking::lock( - RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), - amount, - )); - - // Execute legacy call, expect only single stake to be executed. - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::bond_and_stake { - contract_h160: smart_contract_address.into(), - amount, - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Stake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract && amount == amount - ); - }); -} - -#[test] -fn unbond_and_unstake_with_two_calls_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Execute legacy call, expect funds to first unstaked, and then unlocked - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::unbond_and_unstake { - contract_h160: smart_contract_address.into(), - amount, - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 2); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Unstake { - smart_contract, - amount, - .. - }if smart_contract == smart_contract && amount == amount - ); - assert_matches!( - events[1].clone(), - pallet_dapp_staking_v3::Event::Unlocking { amount, .. } if amount == amount - ); - }); -} - -#[test] -fn unbond_and_unstake_with_single_calls_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Unstake the entire amount, so only unlock call is expected. - assert_ok!(DappStaking::unstake( - RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), - smart_contract.clone(), - amount, - )); - - // Execute legacy call, expect funds to be unlocked - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::unbond_and_unstake { - contract_h160: smart_contract_address.into(), - amount, - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Unlocking { amount, .. } if amount == amount - ); - }); -} - -#[test] -fn withdraw_unbonded_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let staker_native = AddressMapper::into_account_id(staker_h160); - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Unlock some amount - assert_ok!(DappStaking::unstake( - RawOrigin::Signed(staker_native.clone()).into(), - smart_contract.clone(), - amount, - )); - let unlock_amount = amount / 7; - assert_ok!(DappStaking::unlock( - RawOrigin::Signed(staker_native.clone()).into(), - unlock_amount, - )); - - // Advance enough into time so unlocking chunk can be claimed - let unlock_block = Ledger::::get(&staker_native).unlocking[0].unlock_block; - run_to_block(unlock_block); - - // Execute legacy call, expect unlocked funds to be claimed back - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::withdraw_unbonded {}, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::ClaimedUnlocked { - amount, - .. - } if amount == unlock_amount - ); - }); -} - -#[test] -fn claim_dapp_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Advance enough eras so we can claim dApp reward - advance_to_era(3); - let claim_era = 2; - - // Execute legacy call, expect dApp rewards to be claimed - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::claim_dapp { - contract_h160: smart_contract_address.into(), - era: claim_era, - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::DAppReward { - era, - smart_contract, - .. - } if era as u128 == claim_era && smart_contract == smart_contract - ); - }); -} - -#[test] -fn claim_staker_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Advance enough eras so we can claim dApp reward - let target_era = 5; - advance_to_era(target_era); - let number_of_claims = (2..target_era).count(); - - // Execute legacy call, expect dApp rewards to be claimed - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::claim_staker { - _contract_h160: smart_contract_address.into(), - }, - ) - .expect_no_logs() - .execute_returns(true); - - // We expect multiple reward to be claimed - let events = dapp_staking_events(); - assert_eq!(events.len(), number_of_claims as usize); - for era in 2..target_era { - assert_matches!( - events[era as usize - 2].clone(), - pallet_dapp_staking_v3::Event::Reward { era, .. } if era == era - ); - } - }); -} - -#[test] -fn withdraw_from_unregistered_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register a dApp for staking - let staker_h160 = ALICE; - let smart_contract_address = H160::repeat_byte(0xFA); - let smart_contract = - ::SmartContract::evm(smart_contract_address); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract.clone(), amount); - - // Unregister the dApp - assert_ok!(DappStaking::unregister( - RawOrigin::Root.into(), - smart_contract.clone() - )); - - // Execute legacy call, expect funds to be unstaked & withdrawn - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::withdraw_from_unregistered { - contract_h160: smart_contract_address.into(), - }, - ) - .expect_no_logs() - .execute_returns(true); - - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::UnstakeFromUnregistered { - smart_contract, - amount, - .. - } if smart_contract == smart_contract && amount == amount - ); - }); -} - -#[test] -fn nomination_transfer_is_ok() { - ExternalityBuilder::build().execute_with(|| { - initialize(); - - // Register the first dApp, and stke on it. - let staker_h160 = ALICE; - let staker_native = AddressMapper::into_account_id(staker_h160); - let smart_contract_address_1 = H160::repeat_byte(0xFA); - let smart_contract_1 = - ::SmartContract::evm(smart_contract_address_1); - let amount = 1_000_000_000_000; - register_and_stake(staker_h160, smart_contract_1.clone(), amount); - - // Register the second dApp. - let smart_contract_address_2 = H160::repeat_byte(0xBF); - let smart_contract_2 = - ::SmartContract::evm(smart_contract_address_2); - assert_ok!(DappStaking::register( - RawOrigin::Root.into(), - staker_native.clone(), - smart_contract_2.clone() - )); - - // 1st scenario - transfer enough amount from the first to second dApp to cover the stake, - // but not enough for full unstake. - let minimum_stake_amount: Balance = - ::MinimumStakeAmount::get(); - - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::nomination_transfer { - origin_contract_h160: smart_contract_address_1.into(), - amount: minimum_stake_amount, - target_contract_h160: smart_contract_address_2.into(), - }, - ) - .expect_no_logs() - .execute_returns(true); - - // We expect the same amount to be staked on the second contract - let events = dapp_staking_events(); - assert_eq!(events.len(), 2); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Unstake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract_1 && amount == minimum_stake_amount - ); - assert_matches!( - events[1].clone(), - pallet_dapp_staking_v3::Event::Stake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract_2 && amount == minimum_stake_amount - ); - - // 2nd scenario - transfer almost the entire amount from the first to second dApp. - // The amount is large enough to trigger full unstake of the first contract. - let unstake_amount = amount - minimum_stake_amount - 1; - let expected_stake_unstake_amount = amount - minimum_stake_amount; - - System::reset_events(); - precompiles() - .prepare_test( - staker_h160, - precompile_address(), - PrecompileCall::nomination_transfer { - origin_contract_h160: smart_contract_address_1.into(), - amount: unstake_amount, - target_contract_h160: smart_contract_address_2.into(), - }, - ) - .expect_no_logs() - .execute_returns(true); - - // We expect the same amount to be staked on the second contract - let events = dapp_staking_events(); - assert_eq!(events.len(), 2); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Unstake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract_1 && amount == expected_stake_unstake_amount - ); - assert_matches!( - events[1].clone(), - pallet_dapp_staking_v3::Event::Stake { - smart_contract, - amount, - .. - } if smart_contract == smart_contract_2 && amount == expected_stake_unstake_amount - ); - }); -} diff --git a/precompiles/dapp-staking-v3/src/test/tests_v2.rs b/precompiles/dapp-staking-v3/src/test/tests_v2.rs index 5977417b5..8d93b5619 100644 --- a/precompiles/dapp-staking-v3/src/test/tests_v2.rs +++ b/precompiles/dapp-staking-v3/src/test/tests_v2.rs @@ -22,205 +22,455 @@ use frame_support::assert_ok; use frame_system::RawOrigin; use precompile_utils::testing::*; use sp_core::H160; +use sp_runtime::traits::Zero; use assert_matches::assert_matches; -use astar_primitives::{dapp_staking::CycleConfiguration, BlockNumber}; -use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber}; +use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber, EraRewards}; #[test] -fn protocol_state_is_ok() { +fn read_current_era_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Prepare some mixed state in the future so not all entries are 'zero' - advance_to_next_period(); - advance_to_next_era(); - - let state = ActiveProtocolState::::get(); - - let expected_outcome = PrecompileProtocolState { - era: state.era.into(), - period: state.period_number().into(), - subperiod: subperiod_id(&state.subperiod()), - }; + precompiles() + .prepare_test( + Alice, + precompile_address(), + PrecompileCall::read_current_era {}, + ) + .expect_no_logs() + .execute_returns(ActiveProtocolState::::get().era); + // advance a few eras, check value again + advance_to_era(7); precompiles() .prepare_test( Alice, precompile_address(), - PrecompileCall::protocol_state {}, + PrecompileCall::read_current_era {}, ) .expect_no_logs() - .execute_returns(expected_outcome); + .execute_returns(ActiveProtocolState::::get().era); }); } #[test] -fn unlocking_period_is_ok() { +fn read_unbonding_period_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); let unlocking_period_in_eras: EraNumber = ::UnlockingPeriod::get(); - let era_length: BlockNumber = - ::CycleConfiguration::blocks_per_era(); - let expected_outcome = era_length * unlocking_period_in_eras; + precompiles() + .prepare_test( + Alice, + precompile_address(), + PrecompileCall::read_unbonding_period {}, + ) + .expect_no_logs() + .execute_returns(unlocking_period_in_eras); + }); +} + +#[test] +fn read_era_reward_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Check historic era for rewards + let era = 3; + advance_to_era(era + 1); + + let span_index = DAppStaking::::era_reward_span_index(era); + + let era_rewards_span = EraRewards::::get(span_index).expect("Entry must exist."); + let expected_reward = era_rewards_span + .get(era) + .map(|r| r.staker_reward_pool + r.dapp_reward_pool) + .expect("It's history era so it must exist."); + assert!(expected_reward > 0, "Sanity check."); precompiles() .prepare_test( Alice, precompile_address(), - PrecompileCall::unlocking_period {}, + PrecompileCall::read_era_reward { era }, ) .expect_no_logs() - .execute_returns(expected_outcome); + .execute_returns(expected_reward); + + // Check current era for rewards, must be zero + precompiles() + .prepare_test( + Alice, + precompile_address(), + PrecompileCall::read_era_reward { era: era + 1 }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); }); } #[test] -fn lock_is_ok() { +fn read_era_staked_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Lock some amount and verify event - let amount = 1234; - System::reset_events(); + let staker_h160 = ALICE; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); + let anchor_era = ActiveProtocolState::::get().era; + + // 1. Current era stake must be zero, since stake is only valid from the next era. precompiles() - .prepare_test(ALICE, precompile_address(), PrecompileCall::lock { amount }) + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_era_staked { era: anchor_era }, + ) .expect_no_logs() - .execute_returns(true); + .execute_returns(Balance::zero()); - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Locked { - amount, - .. - } if amount == amount - ); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_era_staked { + era: anchor_era + 1, + }, + ) + .expect_no_logs() + .execute_returns(amount); + + // 2. Advance to next era, and check next era after the anchor. + advance_to_era(anchor_era + 5); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_era_staked { + era: anchor_era + 1, + }, + ) + .expect_no_logs() + .execute_returns(amount); + + // 3. Check era after the next one, must throw an error. + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_era_staked { + era: ActiveProtocolState::::get().era + 2, + }, + ) + .expect_no_logs() + .execute_reverts(|output| output == b"Era is in the future"); }); } #[test] -fn unlock_is_ok() { +fn read_staked_amount_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - let lock_amount = 1234; - assert_ok!(DappStaking::lock( - RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), - lock_amount, - )); + let staker_h160 = ALICE; + let dynamic_addresses = into_dynamic_addresses(staker_h160); + + // 1. Sanity checks - must be zero before anything is staked. + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount { + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + } + + // 2. Stake some amount and check again + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount { + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(amount); + } + + // 3. Advance into next period, it should be reset back to zero + advance_to_next_period(); + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount { + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + } + }); +} + +#[test] +fn read_staked_amount_on_contract_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + let staker_h160 = ALICE; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let dynamic_addresses = into_dynamic_addresses(staker_h160); + + // 1. Sanity checks - must be zero before anything is staked. + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount_on_contract { + contract_h160: smart_contract_address.into(), + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + } + + // 2. Stake some amount and check again + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount_on_contract { + contract_h160: smart_contract_address.into(), + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(amount); + } + + // 3. Advance into next period, it should be reset back to zero + advance_to_next_period(); + for staker in &dynamic_addresses { + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_staked_amount_on_contract { + contract_h160: smart_contract_address.into(), + staker: staker.clone(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + } + }); +} + +#[test] +fn read_contract_stake_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + let staker_h160 = ALICE; + let smart_contract_address = H160::repeat_byte(0xFA); + + // 1. Sanity checks - must be zero before anything is staked. + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_contract_stake { + contract_h160: smart_contract_address.into(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + + // 2. Stake some amount and check again + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_contract_stake { + contract_h160: smart_contract_address.into(), + }, + ) + .expect_no_logs() + .execute_returns(amount); + + // 3. Advance into next period, it should be reset back to zero + advance_to_next_period(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::read_contract_stake { + contract_h160: smart_contract_address.into(), + }, + ) + .expect_no_logs() + .execute_returns(Balance::zero()); + }); +} + +#[test] +fn register_is_unsupported() { + ExternalityBuilder::build().execute_with(|| { + initialize(); - // Unlock some amount and verify event - System::reset_events(); - let unlock_amount = 1234 / 7; precompiles() .prepare_test( ALICE, precompile_address(), - PrecompileCall::unlock { - amount: unlock_amount, + PrecompileCall::register { + _address: Default::default(), }, ) .expect_no_logs() - .execute_returns(true); + .execute_reverts(|output| output == b"register via evm precompile is not allowed"); + }); +} - let events = dapp_staking_events(); - assert_eq!(events.len(), 1); - assert_matches!( - events[0].clone(), - pallet_dapp_staking_v3::Event::Unlocking { - amount, - .. - } if amount == unlock_amount - ); +#[test] +fn set_reward_destination_is_unsupported() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + precompiles() + .prepare_test( + ALICE, + precompile_address(), + PrecompileCall::set_reward_destination { _destination: 0 }, + ) + .expect_no_logs() + .execute_reverts(|output| { + output == b"Setting reward destination is no longer supported." + }); }); } #[test] -fn claim_unlocked_is_ok() { +fn bond_and_stake_with_two_calls_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Lock/unlock some amount to create unlocking chunk - let amount = 1234; - assert_ok!(DappStaking::lock( - RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), - amount, - )); - assert_ok!(DappStaking::unlock( - RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), - amount, + // Register a dApp for staking + let staker_h160 = ALICE; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + assert_ok!(DappStaking::register( + RawOrigin::Root.into(), + AddressMapper::into_account_id(staker_h160), + smart_contract.clone() )); - // Advance enough into time so unlocking chunk can be claimed - let unlock_block = - Ledger::::get(&AddressMapper::into_account_id(ALICE)).unlocking[0].unlock_block; - run_to_block(unlock_block); + // Lock some amount, but not enough to cover the `bond_and_stake` call. + let pre_lock_amount = 500; + let stake_amount = 1_000_000; + assert_ok!(DappStaking::lock( + RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), + pre_lock_amount, + )); - // Claim unlocked chunk and verify event + // Execute legacy call, expect missing funds to be locked. System::reset_events(); precompiles() .prepare_test( - ALICE, + staker_h160, precompile_address(), - PrecompileCall::claim_unlocked {}, + PrecompileCall::bond_and_stake { + contract_h160: smart_contract_address.into(), + amount: stake_amount, + }, ) .expect_no_logs() .execute_returns(true); let events = dapp_staking_events(); - assert_eq!(events.len(), 1); + assert_eq!(events.len(), 2); + let additional_lock_amount = stake_amount - pre_lock_amount; assert_matches!( events[0].clone(), - pallet_dapp_staking_v3::Event::ClaimedUnlocked { + pallet_dapp_staking_v3::Event::Locked { amount, .. - } if amount == amount + } if amount == additional_lock_amount + ); + assert_matches!( + events[1].clone(), + pallet_dapp_staking_v3::Event::Stake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract && amount == stake_amount ); }); } #[test] -fn stake_is_ok() { +fn bond_and_stake_with_single_call_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_h160 = H160::repeat_byte(0xFA); + let smart_contract_address = H160::repeat_byte(0xFA); let smart_contract = - ::SmartContract::evm(smart_contract_h160); + ::SmartContract::evm(smart_contract_address); assert_ok!(DappStaking::register( RawOrigin::Root.into(), AddressMapper::into_account_id(staker_h160), smart_contract.clone() )); - // Lock some amount which will be used for staking - let amount = 2000; + // Lock enough amount to cover `bond_and_stake` call. + let amount = 3000; assert_ok!(DappStaking::lock( RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), amount, )); - let smart_contract_v2 = SmartContractV2 { - contract_type: SmartContractTypes::Evm, - address: smart_contract_h160.as_bytes().try_into().unwrap(), - }; - - // Stake some amount and verify event + // Execute legacy call, expect only single stake to be executed. System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::stake { - smart_contract: smart_contract_v2, + PrecompileCall::bond_and_stake { + contract_h160: smart_contract_address.into(), amount, }, ) @@ -241,47 +491,26 @@ fn stake_is_ok() { } #[test] -fn unstake_is_ok() { +fn unbond_and_unstake_with_two_calls_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), - ); - assert_ok!(DappStaking::register( - RawOrigin::Root.into(), - AddressMapper::into_account_id(staker_h160), - smart_contract.clone() - )); - - // Lock & stake some amount - let amount = 2000; - assert_ok!(DappStaking::lock( - RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), - amount, - )); - assert_ok!(DappStaking::stake( - RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), - smart_contract.clone(), - amount, - )); - - let smart_contract_v2 = SmartContractV2 { - contract_type: SmartContractTypes::Wasm, - address: smart_contract_address.into(), - }; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); - // Unstake some amount and verify event + // Execute legacy call, expect funds to first unstaked, and then unlocked System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::unstake { - smart_contract: smart_contract_v2, + PrecompileCall::unbond_and_unstake { + contract_h160: smart_contract_address.into(), amount, }, ) @@ -289,91 +518,102 @@ fn unstake_is_ok() { .execute_returns(true); let events = dapp_staking_events(); - assert_eq!(events.len(), 1); + assert_eq!(events.len(), 2); assert_matches!( events[0].clone(), pallet_dapp_staking_v3::Event::Unstake { smart_contract, amount, .. - } if smart_contract == smart_contract && amount == amount + }if smart_contract == smart_contract && amount == amount + ); + assert_matches!( + events[1].clone(), + pallet_dapp_staking_v3::Event::Unlocking { amount, .. } if amount == amount ); }); } #[test] -fn claim_staker_rewards_is_ok() { +fn unbond_and_unstake_with_single_calls_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Register a dApp and stake on it + // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), - ); - let amount = 1234; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; register_and_stake(staker_h160, smart_contract.clone(), amount); - // Advance a few eras so we can claim a few rewards - let target_era = 7; - advance_to_era(target_era); - let number_of_claims = (2..target_era).count(); + // Unstake the entire amount, so only unlock call is expected. + assert_ok!(DappStaking::unstake( + RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), + smart_contract.clone(), + amount, + )); - // Claim staker rewards and verify events + // Execute legacy call, expect funds to be unlocked System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::claim_staker_rewards {}, + PrecompileCall::unbond_and_unstake { + contract_h160: smart_contract_address.into(), + amount, + }, ) .expect_no_logs() .execute_returns(true); - // We expect multiple reward to be claimed let events = dapp_staking_events(); - assert_eq!(events.len(), number_of_claims as usize); - for era in 2..target_era { - assert_matches!( - events[era as usize - 2].clone(), - pallet_dapp_staking_v3::Event::Reward { era, .. } if era == era - ); - } + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Unlocking { amount, .. } if amount == amount + ); }); } #[test] -fn claim_bonus_reward_is_ok() { +fn withdraw_unbonded_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Register a dApp and stake on it, loyally + // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), - ); - let amount = 1234; + let staker_native = AddressMapper::into_account_id(staker_h160); + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; register_and_stake(staker_h160, smart_contract.clone(), amount); - // Advance to the next period - advance_to_next_period(); + // Unlock some amount + assert_ok!(DappStaking::unstake( + RawOrigin::Signed(staker_native.clone()).into(), + smart_contract.clone(), + amount, + )); + let unlock_amount = amount / 7; + assert_ok!(DappStaking::unlock( + RawOrigin::Signed(staker_native.clone()).into(), + unlock_amount, + )); - let smart_contract_v2 = SmartContractV2 { - contract_type: SmartContractTypes::Wasm, - address: smart_contract_address.into(), - }; + // Advance enough into time so unlocking chunk can be claimed + let unlock_block = Ledger::::get(&staker_native).unlocking[0].unlock_block; + run_to_block(unlock_block); - // Claim bonus reward and verify event + // Execute legacy call, expect unlocked funds to be claimed back System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::claim_bonus_reward { - smart_contract: smart_contract_v2, - }, + PrecompileCall::withdraw_unbonded {}, ) .expect_no_logs() .execute_returns(true); @@ -382,43 +622,40 @@ fn claim_bonus_reward_is_ok() { assert_eq!(events.len(), 1); assert_matches!( events[0].clone(), - pallet_dapp_staking_v3::Event::BonusReward { smart_contract, .. } if smart_contract == smart_contract + pallet_dapp_staking_v3::Event::ClaimedUnlocked { + amount, + .. + } if amount == unlock_amount ); }); } #[test] -fn claim_dapp_reward_is_ok() { +fn claim_dapp_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Register a dApp and stake on it + // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), - ); - let amount = 1234; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; register_and_stake(staker_h160, smart_contract.clone(), amount); - // Advance to 3rd era so we claim rewards for the 2nd era + // Advance enough eras so we can claim dApp reward advance_to_era(3); + let claim_era = 2; - let smart_contract_v2 = SmartContractV2 { - contract_type: SmartContractTypes::Wasm, - address: smart_contract_address.into(), - }; - - // Claim dApp reward and verify event - let claim_era: EraNumber = 2; + // Execute legacy call, expect dApp rewards to be claimed System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::claim_dapp_reward { - smart_contract: smart_contract_v2, - era: claim_era.into(), + PrecompileCall::claim_dapp { + contract_h160: smart_contract_address.into(), + era: claim_era, }, ) .expect_no_logs() @@ -428,23 +665,69 @@ fn claim_dapp_reward_is_ok() { assert_eq!(events.len(), 1); assert_matches!( events[0].clone(), - pallet_dapp_staking_v3::Event::DAppReward { era, smart_contract, .. } if era == claim_era && smart_contract == smart_contract + pallet_dapp_staking_v3::Event::DAppReward { + era, + smart_contract, + .. + } if era as u128 == claim_era && smart_contract == smart_contract ); }); } #[test] -fn unstake_from_unregistered_is_ok() { +fn claim_staker_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Register a dApp and stake on it + // Register a dApp for staking let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), - ); - let amount = 1234; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Advance enough eras so we can claim dApp reward + let target_era = 5; + advance_to_era(target_era); + let number_of_claims = (2..target_era).count(); + + // Execute legacy call, expect dApp rewards to be claimed + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::claim_staker { + _contract_h160: smart_contract_address.into(), + }, + ) + .expect_no_logs() + .execute_returns(true); + + // We expect multiple reward to be claimed + let events = dapp_staking_events(); + assert_eq!(events.len(), number_of_claims as usize); + for era in 2..target_era { + assert_matches!( + events[era as usize - 2].clone(), + pallet_dapp_staking_v3::Event::Reward { era, .. } if era == era + ); + } + }); +} + +#[test] +fn withdraw_from_unregistered_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp for staking + let staker_h160 = ALICE; + let smart_contract_address = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_address); + let amount = 1_000_000_000_000; register_and_stake(staker_h160, smart_contract.clone(), amount); // Unregister the dApp @@ -453,19 +736,14 @@ fn unstake_from_unregistered_is_ok() { smart_contract.clone() )); - let smart_contract_v2 = SmartContractV2 { - contract_type: SmartContractTypes::Wasm, - address: smart_contract_address.into(), - }; - - // Unstake from the unregistered dApp and verify event + // Execute legacy call, expect funds to be unstaked & withdrawn System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::unstake_from_unregistered { - smart_contract: smart_contract_v2, + PrecompileCall::withdraw_from_unregistered { + contract_h160: smart_contract_address.into(), }, ) .expect_no_logs() @@ -475,52 +753,115 @@ fn unstake_from_unregistered_is_ok() { assert_eq!(events.len(), 1); assert_matches!( events[0].clone(), - pallet_dapp_staking_v3::Event::UnstakeFromUnregistered { smart_contract, amount, .. } if smart_contract == smart_contract && amount == amount + pallet_dapp_staking_v3::Event::UnstakeFromUnregistered { + smart_contract, + amount, + .. + } if smart_contract == smart_contract && amount == amount ); }); } #[test] -fn cleanup_expired_entries_is_ok() { +fn nomination_transfer_is_ok() { ExternalityBuilder::build().execute_with(|| { initialize(); - // Advance over to the Build&Earn subperiod - advance_to_next_subperiod(); - assert_eq!( - ActiveProtocolState::::get().subperiod(), - Subperiod::BuildAndEarn, - "Sanity check." - ); - - // Register a dApp and stake on it + // Register the first dApp, and stke on it. let staker_h160 = ALICE; - let smart_contract_address = [0xAF; 32]; - let smart_contract = ::SmartContract::wasm( - smart_contract_address.into(), + let staker_native = AddressMapper::into_account_id(staker_h160); + let smart_contract_address_1 = H160::repeat_byte(0xFA); + let smart_contract_1 = + ::SmartContract::evm(smart_contract_address_1); + let amount = 1_000_000_000_000; + register_and_stake(staker_h160, smart_contract_1.clone(), amount); + + // Register the second dApp. + let smart_contract_address_2 = H160::repeat_byte(0xBF); + let smart_contract_2 = + ::SmartContract::evm(smart_contract_address_2); + assert_ok!(DappStaking::register( + RawOrigin::Root.into(), + staker_native.clone(), + smart_contract_2.clone() + )); + + // 1st scenario - transfer enough amount from the first to second dApp to cover the stake, + // but not enough for full unstake. + let minimum_stake_amount: Balance = + ::MinimumStakeAmount::get(); + + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::nomination_transfer { + origin_contract_h160: smart_contract_address_1.into(), + amount: minimum_stake_amount, + target_contract_h160: smart_contract_address_2.into(), + }, + ) + .expect_no_logs() + .execute_returns(true); + + // We expect the same amount to be staked on the second contract + let events = dapp_staking_events(); + assert_eq!(events.len(), 2); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Unstake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract_1 && amount == minimum_stake_amount + ); + assert_matches!( + events[1].clone(), + pallet_dapp_staking_v3::Event::Stake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract_2 && amount == minimum_stake_amount ); - let amount = 1234; - register_and_stake(staker_h160, smart_contract.clone(), amount); - // Advance over to the next period so the entry for dApp becomes expired - advance_to_next_period(); + // 2nd scenario - transfer almost the entire amount from the first to second dApp. + // The amount is large enough to trigger full unstake of the first contract. + let unstake_amount = amount - minimum_stake_amount - 1; + let expected_stake_unstake_amount = amount - minimum_stake_amount; - // Cleanup single expired entry and verify event System::reset_events(); precompiles() .prepare_test( staker_h160, precompile_address(), - PrecompileCall::cleanup_expired_entries {}, + PrecompileCall::nomination_transfer { + origin_contract_h160: smart_contract_address_1.into(), + amount: unstake_amount, + target_contract_h160: smart_contract_address_2.into(), + }, ) .expect_no_logs() .execute_returns(true); + // We expect the same amount to be staked on the second contract let events = dapp_staking_events(); - assert_eq!(events.len(), 1); + assert_eq!(events.len(), 2); assert_matches!( events[0].clone(), - pallet_dapp_staking_v3::Event::ExpiredEntriesRemoved { count, .. } if count == 1 + pallet_dapp_staking_v3::Event::Unstake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract_1 && amount == expected_stake_unstake_amount + ); + assert_matches!( + events[1].clone(), + pallet_dapp_staking_v3::Event::Stake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract_2 && amount == expected_stake_unstake_amount ); }); } diff --git a/precompiles/dapp-staking-v3/src/test/tests_v3.rs b/precompiles/dapp-staking-v3/src/test/tests_v3.rs new file mode 100644 index 000000000..5977417b5 --- /dev/null +++ b/precompiles/dapp-staking-v3/src/test/tests_v3.rs @@ -0,0 +1,526 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +extern crate alloc; +use crate::{test::mock::*, *}; +use frame_support::assert_ok; +use frame_system::RawOrigin; +use precompile_utils::testing::*; +use sp_core::H160; + +use assert_matches::assert_matches; + +use astar_primitives::{dapp_staking::CycleConfiguration, BlockNumber}; +use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber}; + +#[test] +fn protocol_state_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Prepare some mixed state in the future so not all entries are 'zero' + advance_to_next_period(); + advance_to_next_era(); + + let state = ActiveProtocolState::::get(); + + let expected_outcome = PrecompileProtocolState { + era: state.era.into(), + period: state.period_number().into(), + subperiod: subperiod_id(&state.subperiod()), + }; + + precompiles() + .prepare_test( + Alice, + precompile_address(), + PrecompileCall::protocol_state {}, + ) + .expect_no_logs() + .execute_returns(expected_outcome); + }); +} + +#[test] +fn unlocking_period_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + let unlocking_period_in_eras: EraNumber = + ::UnlockingPeriod::get(); + let era_length: BlockNumber = + ::CycleConfiguration::blocks_per_era(); + + let expected_outcome = era_length * unlocking_period_in_eras; + + precompiles() + .prepare_test( + Alice, + precompile_address(), + PrecompileCall::unlocking_period {}, + ) + .expect_no_logs() + .execute_returns(expected_outcome); + }); +} + +#[test] +fn lock_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Lock some amount and verify event + let amount = 1234; + System::reset_events(); + precompiles() + .prepare_test(ALICE, precompile_address(), PrecompileCall::lock { amount }) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Locked { + amount, + .. + } if amount == amount + ); + }); +} + +#[test] +fn unlock_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + let lock_amount = 1234; + assert_ok!(DappStaking::lock( + RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), + lock_amount, + )); + + // Unlock some amount and verify event + System::reset_events(); + let unlock_amount = 1234 / 7; + precompiles() + .prepare_test( + ALICE, + precompile_address(), + PrecompileCall::unlock { + amount: unlock_amount, + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Unlocking { + amount, + .. + } if amount == unlock_amount + ); + }); +} + +#[test] +fn claim_unlocked_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Lock/unlock some amount to create unlocking chunk + let amount = 1234; + assert_ok!(DappStaking::lock( + RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), + amount, + )); + assert_ok!(DappStaking::unlock( + RawOrigin::Signed(AddressMapper::into_account_id(ALICE)).into(), + amount, + )); + + // Advance enough into time so unlocking chunk can be claimed + let unlock_block = + Ledger::::get(&AddressMapper::into_account_id(ALICE)).unlocking[0].unlock_block; + run_to_block(unlock_block); + + // Claim unlocked chunk and verify event + System::reset_events(); + precompiles() + .prepare_test( + ALICE, + precompile_address(), + PrecompileCall::claim_unlocked {}, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::ClaimedUnlocked { + amount, + .. + } if amount == amount + ); + }); +} + +#[test] +fn stake_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp for staking + let staker_h160 = ALICE; + let smart_contract_h160 = H160::repeat_byte(0xFA); + let smart_contract = + ::SmartContract::evm(smart_contract_h160); + assert_ok!(DappStaking::register( + RawOrigin::Root.into(), + AddressMapper::into_account_id(staker_h160), + smart_contract.clone() + )); + + // Lock some amount which will be used for staking + let amount = 2000; + assert_ok!(DappStaking::lock( + RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), + amount, + )); + + let smart_contract_v2 = SmartContractV2 { + contract_type: SmartContractTypes::Evm, + address: smart_contract_h160.as_bytes().try_into().unwrap(), + }; + + // Stake some amount and verify event + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::stake { + smart_contract: smart_contract_v2, + amount, + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Stake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract && amount == amount + ); + }); +} + +#[test] +fn unstake_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp for staking + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + assert_ok!(DappStaking::register( + RawOrigin::Root.into(), + AddressMapper::into_account_id(staker_h160), + smart_contract.clone() + )); + + // Lock & stake some amount + let amount = 2000; + assert_ok!(DappStaking::lock( + RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), + amount, + )); + assert_ok!(DappStaking::stake( + RawOrigin::Signed(AddressMapper::into_account_id(staker_h160)).into(), + smart_contract.clone(), + amount, + )); + + let smart_contract_v2 = SmartContractV2 { + contract_type: SmartContractTypes::Wasm, + address: smart_contract_address.into(), + }; + + // Unstake some amount and verify event + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::unstake { + smart_contract: smart_contract_v2, + amount, + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::Unstake { + smart_contract, + amount, + .. + } if smart_contract == smart_contract && amount == amount + ); + }); +} + +#[test] +fn claim_staker_rewards_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp and stake on it + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + let amount = 1234; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Advance a few eras so we can claim a few rewards + let target_era = 7; + advance_to_era(target_era); + let number_of_claims = (2..target_era).count(); + + // Claim staker rewards and verify events + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::claim_staker_rewards {}, + ) + .expect_no_logs() + .execute_returns(true); + + // We expect multiple reward to be claimed + let events = dapp_staking_events(); + assert_eq!(events.len(), number_of_claims as usize); + for era in 2..target_era { + assert_matches!( + events[era as usize - 2].clone(), + pallet_dapp_staking_v3::Event::Reward { era, .. } if era == era + ); + } + }); +} + +#[test] +fn claim_bonus_reward_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp and stake on it, loyally + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + let amount = 1234; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Advance to the next period + advance_to_next_period(); + + let smart_contract_v2 = SmartContractV2 { + contract_type: SmartContractTypes::Wasm, + address: smart_contract_address.into(), + }; + + // Claim bonus reward and verify event + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::claim_bonus_reward { + smart_contract: smart_contract_v2, + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::BonusReward { smart_contract, .. } if smart_contract == smart_contract + ); + }); +} + +#[test] +fn claim_dapp_reward_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp and stake on it + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + let amount = 1234; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Advance to 3rd era so we claim rewards for the 2nd era + advance_to_era(3); + + let smart_contract_v2 = SmartContractV2 { + contract_type: SmartContractTypes::Wasm, + address: smart_contract_address.into(), + }; + + // Claim dApp reward and verify event + let claim_era: EraNumber = 2; + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::claim_dapp_reward { + smart_contract: smart_contract_v2, + era: claim_era.into(), + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::DAppReward { era, smart_contract, .. } if era == claim_era && smart_contract == smart_contract + ); + }); +} + +#[test] +fn unstake_from_unregistered_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Register a dApp and stake on it + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + let amount = 1234; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Unregister the dApp + assert_ok!(DappStaking::unregister( + RawOrigin::Root.into(), + smart_contract.clone() + )); + + let smart_contract_v2 = SmartContractV2 { + contract_type: SmartContractTypes::Wasm, + address: smart_contract_address.into(), + }; + + // Unstake from the unregistered dApp and verify event + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::unstake_from_unregistered { + smart_contract: smart_contract_v2, + }, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::UnstakeFromUnregistered { smart_contract, amount, .. } if smart_contract == smart_contract && amount == amount + ); + }); +} + +#[test] +fn cleanup_expired_entries_is_ok() { + ExternalityBuilder::build().execute_with(|| { + initialize(); + + // Advance over to the Build&Earn subperiod + advance_to_next_subperiod(); + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn, + "Sanity check." + ); + + // Register a dApp and stake on it + let staker_h160 = ALICE; + let smart_contract_address = [0xAF; 32]; + let smart_contract = ::SmartContract::wasm( + smart_contract_address.into(), + ); + let amount = 1234; + register_and_stake(staker_h160, smart_contract.clone(), amount); + + // Advance over to the next period so the entry for dApp becomes expired + advance_to_next_period(); + + // Cleanup single expired entry and verify event + System::reset_events(); + precompiles() + .prepare_test( + staker_h160, + precompile_address(), + PrecompileCall::cleanup_expired_entries {}, + ) + .expect_no_logs() + .execute_returns(true); + + let events = dapp_staking_events(); + assert_eq!(events.len(), 1); + assert_matches!( + events[0].clone(), + pallet_dapp_staking_v3::Event::ExpiredEntriesRemoved { count, .. } if count == 1 + ); + }); +} From 8f32a7d3f3b9798b677d2d3dad700d2ad70f80a2 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 8 Jan 2024 15:57:04 +0100 Subject: [PATCH 04/16] Typo & renaming --- pallets/dapp-staking-v3/src/lib.rs | 14 +++++++------- pallets/dapp-staking-v3/src/test/testing_utils.rs | 4 ++-- pallets/dapp-staking-v3/src/test/tests.rs | 2 +- pallets/dapp-staking-v3/src/test/tests_types.rs | 4 ++-- pallets/dapp-staking-v3/src/types.rs | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 9b23375d3..0a43436d6 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -315,7 +315,7 @@ pub mod pallet { UnavailableStakeFunds, /// There are unclaimed rewards remaining from past eras or periods. They should be claimed before attempting any stake modification again. UnclaimedRewards, - /// An unexpected error occured while trying to stake. + /// An unexpected error occurred while trying to stake. InternalStakeError, /// Total staked amount on contract is below the minimum required value. InsufficientStakeAmount, @@ -327,7 +327,7 @@ pub mod pallet { UnstakeAmountTooLarge, /// Account has no staking information for the contract. NoStakingInfo, - /// An unexpected error occured while trying to unstake. + /// An unexpected error occurred while trying to unstake. InternalUnstakeError, /// Rewards are no longer claimable since they are too old. RewardExpired, @@ -335,18 +335,18 @@ pub mod pallet { RewardPayoutFailed, /// There are no claimable rewards. NoClaimableRewards, - /// An unexpected error occured while trying to claim staker rewards. + /// An unexpected error occurred while trying to claim staker rewards. InternalClaimStakerError, /// Account is has no eligible stake amount for bonus reward. NotEligibleForBonusReward, - /// An unexpected error occured while trying to claim bonus reward. + /// An unexpected error occurred while trying to claim bonus reward. InternalClaimBonusError, /// Claim era is invalid - it must be in history, and rewards must exist for it. InvalidClaimEra, /// No dApp tier info exists for the specified era. This can be because era has expired /// or because during the specified era there were no eligible rewards or protocol wasn't active. NoDAppTierInfo, - /// An unexpected error occured while trying to claim dApp reward. + /// An unexpected error occurred while trying to claim dApp reward. InternalClaimDAppError, /// Contract is still active, not unregistered. ContractStillActive, @@ -632,7 +632,7 @@ pub mod pallet { owner: owner.clone(), id: dapp_id, state: DAppState::Registered, - reward_destination: None, + reward_beneficiary: None, }, ); @@ -671,7 +671,7 @@ pub mod pallet { ensure!(dapp_info.owner == dev_account, Error::::OriginNotOwner); - dapp_info.reward_destination = beneficiary.clone(); + dapp_info.reward_beneficiary = beneficiary.clone(); Ok(()) }, diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 8eadc3e66..83972f376 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -110,7 +110,7 @@ pub(crate) fn assert_register(owner: AccountId, smart_contract: &MockSmartContra assert_eq!(dapp_info.state, DAppState::Registered); assert_eq!(dapp_info.owner, owner); assert_eq!(dapp_info.id, pre_snapshot.next_dapp_id); - assert!(dapp_info.reward_destination.is_none()); + assert!(dapp_info.reward_beneficiary.is_none()); assert_eq!(pre_snapshot.next_dapp_id + 1, NextDAppId::::get()); assert_eq!( @@ -142,7 +142,7 @@ pub(crate) fn assert_set_dapp_reward_beneficiary( assert_eq!( IntegratedDApps::::get(&smart_contract) .unwrap() - .reward_destination, + .reward_beneficiary, beneficiary ); } diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 8839753b0..1a2a4cd4a 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -332,7 +332,7 @@ fn set_dapp_reward_beneficiary_for_contract_is_ok() { // Update beneficiary assert!(IntegratedDApps::::get(&smart_contract) .unwrap() - .reward_destination + .reward_beneficiary .is_none()); assert_set_dapp_reward_beneficiary(owner, &smart_contract, Some(3)); assert_set_dapp_reward_beneficiary(owner, &smart_contract, Some(5)); diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 5dc3eea11..9d9a5d2e7 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -158,14 +158,14 @@ fn dapp_info_basic_checks() { owner, id: 7, state: DAppState::Registered, - reward_destination: None, + reward_beneficiary: None, }; // Owner receives reward in case no beneficiary is set assert_eq!(*dapp_info.reward_beneficiary(), owner); // Beneficiary receives rewards in case it is set - dapp_info.reward_destination = Some(beneficiary); + dapp_info.reward_beneficiary = Some(beneficiary); assert_eq!(*dapp_info.reward_beneficiary(), beneficiary); // Check if dApp is registered diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index bb9e48469..1b88199a6 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -273,13 +273,13 @@ pub struct DAppInfo { /// Current state of the dApp. pub state: DAppState, // If `None`, rewards goes to the developer account, otherwise to the account Id in `Some`. - pub reward_destination: Option, + pub reward_beneficiary: Option, } impl DAppInfo { /// Reward destination account for this dApp. pub fn reward_beneficiary(&self) -> &AccountId { - match &self.reward_destination { + match &self.reward_beneficiary { Some(account_id) => account_id, None => &self.owner, } From de5cf1a99c391efde2e62f8043a0d31ea59e4bec Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 8 Jan 2024 16:14:02 +0100 Subject: [PATCH 05/16] More review adjustments --- pallets/dapp-staking-v3/src/lib.rs | 16 +++++-------- pallets/inflation/src/lib.rs | 38 +++++++++++------------------- pallets/inflation/src/tests.rs | 10 ++++---- 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 0a43436d6..e4e192c48 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -745,10 +745,7 @@ pub mod pallet { let mut dapp_info = IntegratedDApps::::get(&smart_contract).ok_or(Error::::ContractNotFound)?; - ensure!( - dapp_info.state == DAppState::Registered, - Error::::NotOperatedDApp - ); + ensure!(dapp_info.is_registered(), Error::::NotOperatedDApp); ContractStake::::remove(&dapp_info.id); @@ -1681,12 +1678,11 @@ pub mod pallet { counter.saturating_inc(); // Skip dApps which don't have ANY amount staked - let stake_amount = match stake_amount.get(era, period) { - Some(stake_amount) if !stake_amount.total().is_zero() => stake_amount, - _ => continue, - }; - - dapp_stakes.push((dapp_id, stake_amount.total())); + if let Some(stake_amount) = stake_amount.get(era, period) { + if !stake_amount.total().is_zero() { + dapp_stakes.push((dapp_id, stake_amount.total())); + } + } } // 2. diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index b643fe5e3..8d278e1c0 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -69,9 +69,9 @@ //! //! ## Rewards //! -//! ### Staker & Treasury Rewards +//! ### Collator & Treasury Rewards //! -//! These are paid out at the begininng of each block & are fixed amounts. +//! These are paid out at the beginning of each block & are fixed amounts. //! //! ### Staker Rewards //! @@ -177,7 +177,7 @@ pub mod pallet { InvalidInflationParameters, } - /// Active inflation configuration parameteres. + /// Active inflation configuration parameters. /// They describe current rewards, when inflation needs to be recalculated, etc. #[pallet::storage] #[pallet::whitelist_storage] @@ -219,7 +219,7 @@ pub mod pallet { T::WeightInfo::hook_without_recalculation() }; - // Benchmarks won't acount for whitelisted storage access so this needs to be added manually. + // Benchmarks won't account for the whitelisted storage access so this needs to be added manually. // // ActiveInflationConfig - 1 DB read let whitelisted_weight = ::DbWeight::get().reads(1); @@ -257,7 +257,7 @@ pub mod pallet { /// /// Must be called by `root` origin. /// - /// Purpose of the call is testing & handling unforseen circumstances. + /// Purpose of the call is testing & handling unforeseen circumstances. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::force_set_inflation_params())] pub fn force_set_inflation_params( @@ -279,7 +279,7 @@ pub mod pallet { /// /// Must be called by `root` origin. /// - /// Purpose of the call is testing & handling unforseen circumstances. + /// Purpose of the call is testing & handling unforeseen circumstances. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::force_inflation_recalculation())] pub fn force_inflation_recalculation(origin: OriginFor) -> DispatchResult { @@ -299,7 +299,7 @@ pub mod pallet { /// /// Must be called by `root` origin. /// - /// Purpose of the call is testing & handling unforseen circumstances. + /// Purpose of the call is testing & handling unforeseen circumstances. /// /// **NOTE:** and a TODO, remove this before deploying on mainnet. #[pallet::call_index(2)] @@ -368,23 +368,13 @@ pub mod pallet { // 3.0 Convert all 'per cycle' values to the correct type (Balance). // Also include a safety check that none of the values is zero since this would cause a division by zero. // The configuration & integration tests must ensure this never happens, so the following code is just an additional safety measure. - let blocks_per_cycle = match T::CycleConfiguration::blocks_per_cycle() { - 0 => Balance::MAX, - blocks_per_cycle => Balance::from(blocks_per_cycle), - }; - + let blocks_per_cycle = Balance::from(T::CycleConfiguration::blocks_per_cycle().max(1)); let build_and_earn_eras_per_cycle = - match T::CycleConfiguration::build_and_earn_eras_per_cycle() { - 0 => Balance::MAX, - build_and_earn_eras_per_cycle => Balance::from(build_and_earn_eras_per_cycle), - }; - - let periods_per_cycle = match T::CycleConfiguration::periods_per_cycle() { - 0 => Balance::MAX, - periods_per_cycle => Balance::from(periods_per_cycle), - }; + Balance::from(T::CycleConfiguration::build_and_earn_eras_per_cycle().max(1)); + let periods_per_cycle = + Balance::from(T::CycleConfiguration::periods_per_cycle().max(1)); - // 3.1. Collator & Treausry rewards per block + // 3.1. Collator & Treasury rewards per block let collator_reward_per_block = collators_emission / blocks_per_cycle; let treasury_reward_per_block = treasury_emission / blocks_per_cycle; @@ -500,7 +490,7 @@ pub struct InflationConfiguration { /// Base staker reward pool per era - this is always provided to stakers, regardless of the total value staked. #[codec(compact)] pub base_staker_reward_pool_per_era: Balance, - /// Adjustabke staker rewards, based on the total value staked. + /// Adjustable staker rewards, based on the total value staked. /// This is provided to the stakers according to formula: 'pool * min(1, total_staked / ideal_staked)'. #[codec(compact)] pub adjustable_staker_reward_pool_per_era: Balance, @@ -612,7 +602,7 @@ impl> OnRuntimeUpgrade for PalletInflatio let inflation_params = P::get(); InflationParams::::put(inflation_params.clone()); - // 2. Calculation inflation config, set it & depossit event + // 2. Calculation inflation config, set it & deposit event let now = frame_system::Pallet::::block_number(); let config = Pallet::::recalculate_inflation(now); ActiveInflationConfig::::put(config.clone()); diff --git a/pallets/inflation/src/tests.rs b/pallets/inflation/src/tests.rs index 518aa369c..db57a25cf 100644 --- a/pallets/inflation/src/tests.rs +++ b/pallets/inflation/src/tests.rs @@ -37,7 +37,7 @@ fn force_set_inflation_params_work() { ExternalityBuilder::build().execute_with(|| { let mut new_params = InflationParams::::get(); new_params.max_inflation_rate = Perquintill::from_percent(20); - assert!(new_params != InflationParams::::get(), "Sanity check"); + assert_ne!(new_params, InflationParams::::get(), "Sanity check"); // Execute call, ensure it works assert_ok!(Inflation::force_set_inflation_params( @@ -118,8 +118,8 @@ fn force_inflation_recalculation_work() { )); let new_config = ActiveInflationConfig::::get(); - assert!( - old_config != new_config, + assert_ne!( + old_config, new_config, "Config should change, otherwise test doesn't make sense." ); @@ -163,8 +163,8 @@ fn inflation_recalculation_occurs_when_exepcted() { Inflation::on_finalize(init_config.recalculation_block - 1); let new_config = ActiveInflationConfig::::get(); - assert!( - new_config != init_config, + assert_ne!( + new_config, init_config, "Recalculation must happen at this point." ); System::assert_last_event(Event::NewInflationConfiguration { config: new_config }.into()); From dcc111bf93cad06ca86cec2e03335f512181d777 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Thu, 11 Jan 2024 17:07:07 +0100 Subject: [PATCH 06/16] Cycle Alignment --- Cargo.lock | 1 - .../rpc/runtime-api/Cargo.toml | 2 - .../rpc/runtime-api/src/lib.rs | 2 +- pallets/dapp-staking-v3/src/lib.rs | 8 +- pallets/dapp-staking-v3/src/test/mock.rs | 16 ++- .../dapp-staking-v3/src/test/testing_utils.rs | 5 +- pallets/dapp-staking-v3/src/types.rs | 14 +-- pallets/inflation/src/benchmarking.rs | 31 ++--- pallets/inflation/src/lib.rs | 107 +++++++++++------- pallets/inflation/src/mock.rs | 12 +- pallets/inflation/src/tests.rs | 36 +++--- pallets/inflation/src/weights.rs | 12 +- primitives/src/dapp_staking.rs | 38 +++++-- runtime/local/src/lib.rs | 31 ++--- runtime/shibuya/src/lib.rs | 19 ++-- .../shibuya/src/weights/pallet_inflation.rs | 4 +- 16 files changed, 193 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01bdaedad..478f34c7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2440,7 +2440,6 @@ name = "dapp-staking-v3-runtime-api" version = "0.0.1-alpha" dependencies = [ "astar-primitives", - "pallet-dapp-staking-v3", "sp-api", "sp-std", ] diff --git a/pallets/dapp-staking-v3/rpc/runtime-api/Cargo.toml b/pallets/dapp-staking-v3/rpc/runtime-api/Cargo.toml index 63ef539a0..244715aa1 100644 --- a/pallets/dapp-staking-v3/rpc/runtime-api/Cargo.toml +++ b/pallets/dapp-staking-v3/rpc/runtime-api/Cargo.toml @@ -15,13 +15,11 @@ sp-api = { workspace = true } sp-std = { workspace = true } astar-primitives = { workspace = true } -pallet-dapp-staking-v3 = { workspace = true } [features] default = ["std"] std = [ "sp-api/std", "sp-std/std", - "pallet-dapp-staking-v3/std", "astar-primitives/std", ] diff --git a/pallets/dapp-staking-v3/rpc/runtime-api/src/lib.rs b/pallets/dapp-staking-v3/rpc/runtime-api/src/lib.rs index d829e2b27..d08c2379e 100644 --- a/pallets/dapp-staking-v3/rpc/runtime-api/src/lib.rs +++ b/pallets/dapp-staking-v3/rpc/runtime-api/src/lib.rs @@ -18,8 +18,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +use astar_primitives::dapp_staking::{DAppId, EraNumber, PeriodNumber, TierId}; use astar_primitives::BlockNumber; -use pallet_dapp_staking_v3::{DAppId, EraNumber, PeriodNumber, TierId}; pub use sp_std::collections::btree_map::BTreeMap; sp_api::decl_runtime_apis! { diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index d2160aa86..6d8c6260f 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -51,7 +51,10 @@ use sp_runtime::{ pub use sp_std::vec::Vec; use astar_primitives::{ - dapp_staking::{CycleConfiguration, SmartContractHandle, StakingRewardHandler}, + dapp_staking::{ + CycleConfiguration, DAppId, EraNumber, Observer as DAppStakingObserver, PeriodNumber, + SmartContractHandle, StakingRewardHandler, TierId, + }, oracle::PriceProvider, Balance, BlockNumber, }; @@ -138,6 +141,9 @@ pub mod pallet { /// Describes era length, subperiods & period length, as well as cycle length. type CycleConfiguration: CycleConfiguration; + /// dApp staking event observers, notified when certain events occur. + type Observers: DAppStakingObserver; + /// Maximum length of a single era reward span length entry. #[pallet::constant] type EraRewardSpanLength: Get; diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 247605e45..1be4b46ea 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -36,7 +36,11 @@ use sp_runtime::{ }; use sp_std::cell::RefCell; -use astar_primitives::{dapp_staking::SmartContract, testing::Header, Balance, BlockNumber}; +use astar_primitives::{ + dapp_staking::{Observer as DappStakingObserver, SmartContract}, + testing::Header, + Balance, BlockNumber, +}; pub(crate) type AccountId = u64; @@ -117,6 +121,7 @@ impl PriceProvider for DummyPriceProvider { thread_local! { pub(crate) static DOES_PAYOUT_SUCCEED: RefCell = RefCell::new(false); + pub(crate) static BLOCK_BEFORE_NEW_ERA: RefCell = RefCell::new(0); } pub struct DummyStakingRewardHandler; @@ -180,6 +185,14 @@ impl CycleConfiguration for DummyCycleConfiguration { } } +pub struct DummyDappStakingObserver; +impl DappStakingObserver for DummyDappStakingObserver { + fn block_before_new_era(next_era: EraNumber) -> Weight { + BLOCK_BEFORE_NEW_ERA.with(|v| *v.borrow_mut() = next_era); + Weight::from_parts(1, 2) + } +} + impl pallet_dapp_staking::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -189,6 +202,7 @@ impl pallet_dapp_staking::Config for Test { type NativePriceProvider = DummyPriceProvider; type StakingRewardHandler = DummyStakingRewardHandler; type CycleConfiguration = DummyCycleConfiguration; + type Observers = DummyDappStakingObserver; type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<10>; diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 83972f376..999122bdb 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -32,7 +32,10 @@ use frame_support::{ use sp_runtime::{traits::Zero, Perbill}; use std::collections::HashMap; -use astar_primitives::{dapp_staking::CycleConfiguration, Balance, BlockNumber}; +use astar_primitives::{ + dapp_staking::{CycleConfiguration, EraNumber, PeriodNumber}, + Balance, BlockNumber, +}; /// Helper struct used to store the entire pallet state snapshot. /// Used when comparison of before/after states is required. diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 1b88199a6..1e9f2ac99 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -73,7 +73,10 @@ use sp_runtime::{ }; pub use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, vec::Vec}; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{ + dapp_staking::{DAppId, EraNumber, PeriodNumber, TierId}, + Balance, BlockNumber, +}; use crate::pallet::Config; @@ -90,15 +93,6 @@ pub type EraRewardSpanFor = EraRewardSpan<::EraRewardSpanLength> // Convenience type for `DAppInfo` usage. pub type DAppInfoFor = DAppInfo<::AccountId>; -/// Era number type -pub type EraNumber = u32; -/// Period number type -pub type PeriodNumber = u32; -/// Dapp Id type -pub type DAppId = u16; -/// Tier Id type -pub type TierId = u8; - /// Simple enum representing errors possible when using sparse bounded vector. #[derive(Debug, PartialEq, Eq)] pub enum AccountLedgerError { diff --git a/pallets/inflation/src/benchmarking.rs b/pallets/inflation/src/benchmarking.rs index 113c5f32a..184ae5cc6 100644 --- a/pallets/inflation/src/benchmarking.rs +++ b/pallets/inflation/src/benchmarking.rs @@ -46,7 +46,7 @@ fn initial_config() { let issuance_safety_cap = total_issuance.saturating_add(params.max_inflation_rate * total_issuance); let config = InflationConfiguration { - recalculation_block: 123, + recalculation_era: 123, issuance_safety_cap, collator_reward_per_block: 11111, treasury_reward_per_block: 33333, @@ -98,46 +98,37 @@ mod benchmarks { initial_config::(); #[extrinsic_call] - _(RawOrigin::Root); + _(RawOrigin::Root, 123); let config = ActiveInflationConfig::::get(); assert_last_event::(Event::::ForcedInflationRecalculation { config }.into()); } #[benchmark] - fn hook_with_recalculation() { + fn recalculation() { initial_config::(); - ActiveInflationConfig::::mutate(|config| { - config.recalculation_block = 0; - }); - let init_issuance = T::Currency::total_issuance(); + let init_recalculation_era = ActiveInflationConfig::::get().recalculation_era; + DoRecalculation::::put(init_recalculation_era); - let block = 1; #[block] { - Pallet::::on_initialize(block); - Pallet::::on_finalize(block); + Pallet::::block_before_new_era(init_recalculation_era); + Pallet::::on_finalize(1); } - assert!(ActiveInflationConfig::::get().recalculation_block > 0); - - // The 'sane' assumption is that at least something will be issued for treasury & collators - assert!(T::Currency::total_issuance() > init_issuance); + assert!(ActiveInflationConfig::::get().recalculation_era > init_recalculation_era); } #[benchmark] - fn hook_without_recalculation() { + fn hooks_without_recalculation() { initial_config::(); - ActiveInflationConfig::::mutate(|config| { - config.recalculation_block = 2; - }); let init_config = ActiveInflationConfig::::get(); let init_issuance = T::Currency::total_issuance(); + DoRecalculation::::kill(); - // Has to be at least 2 blocks less than the recalculation block. - let block = 0; + let block = 1; #[block] { Pallet::::on_initialize(block); diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 8d278e1c0..97565825e 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -34,7 +34,7 @@ //! E.g. if 'yearly' inflation is set to be 7%, and total issuance is 200 ASTR, then the max inflation for that cycle will be 14 ASTR. //! //! Each cycle consists of one or more `periods`. -//! Periods are integral part of dApp staking protocol, allowing dApps to promotove themselves, attract stakers and earn rewards. +//! Periods are integral part of dApp staking protocol, allowing dApps to promote themselves, attract stakers and earn rewards. //! At the end of each period, all stakes are reset, and dApps need to repeat the process. //! //! Each period consists of two subperiods: `Voting` and `Build&Earn`. @@ -99,7 +99,9 @@ pub use pallet::*; use astar_primitives::{ - dapp_staking::{CycleConfiguration, StakingRewardHandler}, + dapp_staking::{ + CycleConfiguration, EraNumber, Observer as DappStakingObserver, StakingRewardHandler, + }, Balance, BlockNumber, }; use frame_support::{ @@ -187,6 +189,11 @@ pub mod pallet { #[pallet::storage] pub type InflationParams = StorageValue<_, InflationParameters, ValueQuery>; + /// Flag indicating whether on the first possible opportunity, recalculation of the inflation config should be done. + #[pallet::storage] + #[pallet::whitelist_storage] + pub type DoRecalculation = StorageValue<_, EraNumber, OptionQuery>; + #[pallet::genesis_config] #[cfg_attr(feature = "std", derive(Default))] pub struct GenesisConfig { @@ -199,8 +206,8 @@ pub mod pallet { fn build(&self) { assert!(self.params.is_valid()); - let now = frame_system::Pallet::::block_number(); - let config = Pallet::::recalculate_inflation(now); + let starting_era = 1; + let config = Pallet::::recalculate_inflation(starting_era); ActiveInflationConfig::::put(config); InflationParams::::put(self.params); @@ -209,34 +216,27 @@ pub mod pallet { #[pallet::hooks] impl Hooks for Pallet { - fn on_initialize(now: BlockNumber) -> Weight { + fn on_initialize(_now: BlockNumber) -> Weight { Self::payout_block_rewards(); - let recalculation_weight = - if Self::is_recalculation_in_next_block(now, &ActiveInflationConfig::::get()) { - T::WeightInfo::hook_with_recalculation() - } else { - T::WeightInfo::hook_without_recalculation() - }; - // Benchmarks won't account for the whitelisted storage access so this needs to be added manually. // // ActiveInflationConfig - 1 DB read - let whitelisted_weight = ::DbWeight::get().reads(1); - - recalculation_weight.saturating_add(whitelisted_weight) + // DoRecalculation - 1 DB read + ::DbWeight::get().reads(2) } - fn on_finalize(now: BlockNumber) { - // Recalculation is done at the block right before the re-calculation is supposed to happen. + fn on_finalize(_now: BlockNumber) { + // Recalculation is done at the block right before a new cycle starts. // This is to ensure all the rewards are paid out according to the new inflation configuration from next block. // // If this was done in `on_initialize`, collator & treasury would receive incorrect rewards for that one block. // // This should be done as late as possible, to ensure all operations that modify issuance are done. - if Self::is_recalculation_in_next_block(now, &ActiveInflationConfig::::get()) { - let config = Self::recalculate_inflation(now); + if let Some(next_era) = DoRecalculation::::get() { + let config = Self::recalculate_inflation(next_era); ActiveInflationConfig::::put(config.clone()); + DoRecalculation::::kill(); Self::deposit_event(Event::::NewInflationConfiguration { config }); } @@ -282,10 +282,13 @@ pub mod pallet { /// Purpose of the call is testing & handling unforeseen circumstances. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::force_inflation_recalculation())] - pub fn force_inflation_recalculation(origin: OriginFor) -> DispatchResult { + pub fn force_inflation_recalculation( + origin: OriginFor, + next_era: EraNumber, + ) -> DispatchResult { ensure_root(origin)?; - let config = Self::recalculate_inflation(frame_system::Pallet::::block_number()); + let config = Self::recalculate_inflation(next_era); ActiveInflationConfig::::put(config.clone()); @@ -319,14 +322,18 @@ pub mod pallet { } impl Pallet { - /// Used to check if inflation recalculation is supposed to happen on the next block. - /// - /// This will be true even if recalculation is overdue, e.g. it should have happened in the current or older block. - fn is_recalculation_in_next_block( - now: BlockNumber, - config: &InflationConfiguration, - ) -> bool { - config.recalculation_block.saturating_sub(now) <= 1 + /// Informs the pallet that the next block will be the first block of a new era. + // TODO: make an interface for this + pub fn block_before_new_era(new_era: EraNumber) -> Weight { + let config = ActiveInflationConfig::::get(); + if config.recalculation_era <= new_era { + DoRecalculation::::put(new_era); + + // Need to account for write into a single whitelisted storage item. + T::WeightInfo::recalculation().saturating_add(T::DbWeight::get().writes(1)) + } else { + Weight::zero() + } } /// Payout block rewards to the beneficiaries. @@ -347,7 +354,7 @@ pub mod pallet { /// Recalculates the inflation based on the total issuance & inflation parameters. /// /// Returns the new inflation configuration. - pub(crate) fn recalculate_inflation(now: BlockNumber) -> InflationConfiguration { + pub(crate) fn recalculate_inflation(next_era: EraNumber) -> InflationConfiguration { let params = InflationParams::::get(); let total_issuance = T::Currency::total_issuance(); @@ -391,11 +398,12 @@ pub mod pallet { let bonus_reward_pool_per_period = bonus_emission / periods_per_cycle; // 4. Block at which the inflation must be recalculated. - let recalculation_block = now.saturating_add(T::CycleConfiguration::blocks_per_cycle()); + let recalculation_era = + next_era.saturating_add(T::CycleConfiguration::blocks_per_cycle()); // 5. Return calculated values InflationConfiguration { - recalculation_block, + recalculation_era, issuance_safety_cap, collator_reward_per_block, treasury_reward_per_block, @@ -429,6 +437,21 @@ pub mod pallet { } } + impl DappStakingObserver for Pallet { + /// Informs the pallet that the next block will be the first block of a new era. + fn block_before_new_era(new_era: EraNumber) -> Weight { + let config = ActiveInflationConfig::::get(); + if config.recalculation_era <= new_era { + DoRecalculation::::put(new_era); + + // Need to account for write into a single whitelisted storage item. + T::WeightInfo::recalculation().saturating_add(T::DbWeight::get().writes(1)) + } else { + Weight::zero() + } + } + } + impl StakingRewardHandler for Pallet { fn staker_and_dapp_reward_pools(total_value_staked: Balance) -> (Balance, Balance) { let config = ActiveInflationConfig::::get(); @@ -458,7 +481,7 @@ pub mod pallet { // This can fail only if the amount is below existential deposit & the account doesn't exist, // or if the account has no provider references. - // In both cases, the reward is lost but this can be ignored since it's extremelly unlikely + // In both cases, the reward is lost but this can be ignored since it's extremely unlikely // to appear and doesn't bring any real harm. T::Currency::deposit_creating(account, reward); Ok(()) @@ -471,9 +494,9 @@ pub mod pallet { #[derive(Encode, Decode, MaxEncodedLen, Default, Copy, Clone, Debug, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct InflationConfiguration { - /// Block number at which the inflation must be recalculated, based on the total issuance at that block. + /// Era number at which the inflation configuration must be recalculated, based on the total issuance at that block. #[codec(compact)] - pub recalculation_block: BlockNumber, + pub recalculation_era: EraNumber, /// Maximum amount of issuance we can have during this cycle. #[codec(compact)] pub issuance_safety_cap: Balance, @@ -592,19 +615,20 @@ pub trait PayoutPerBlock { #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; pub struct PalletInflationInitConfig(PhantomData<(T, P)>); -impl> OnRuntimeUpgrade for PalletInflationInitConfig { +impl> OnRuntimeUpgrade + for PalletInflationInitConfig +{ fn on_runtime_upgrade() -> Weight { if Pallet::::on_chain_storage_version() >= STORAGE_VERSION { return T::DbWeight::get().reads(1); } // 1. Get & set inflation parameters - let inflation_params = P::get(); + let (inflation_params, next_era) = P::get(); // TODO: re-check this later, whether it will be next or current era InflationParams::::put(inflation_params.clone()); // 2. Calculation inflation config, set it & deposit event - let now = frame_system::Pallet::::block_number(); - let config = Pallet::::recalculate_inflation(now); + let config = Pallet::::recalculate_inflation(next_era); ActiveInflationConfig::::put(config.clone()); Pallet::::deposit_event(Event::::NewInflationConfiguration { config }); @@ -614,8 +638,7 @@ impl> OnRuntimeUpgrade for PalletInflatio log::info!("Inflation pallet storage initialized."); - T::WeightInfo::hook_with_recalculation() - .saturating_add(T::DbWeight::get().reads_writes(1, 2)) + T::WeightInfo::recalculation().saturating_add(T::DbWeight::get().reads_writes(1, 2)) } #[cfg(feature = "try-runtime")] @@ -626,3 +649,5 @@ impl> OnRuntimeUpgrade for PalletInflatio Ok(()) } } + +// TODO: add migration for Shibuya, to set proper next era diff --git a/pallets/inflation/src/mock.rs b/pallets/inflation/src/mock.rs index 3cac1bca8..37588f12d 100644 --- a/pallets/inflation/src/mock.rs +++ b/pallets/inflation/src/mock.rs @@ -53,7 +53,7 @@ pub const INIT_PARAMS: InflationParameters = InflationParameters { /// Initial inflation config set by the mock. pub const INIT_CONFIG: InflationConfiguration = InflationConfiguration { - recalculation_block: 100, + recalculation_era: 100, issuance_safety_cap: 1_000_000, collator_reward_per_block: 1000, treasury_reward_per_block: 1500, @@ -196,13 +196,3 @@ impl ExternalityBuilder { ext } } - -/// Advance to the specified block number. -/// Function assumes first block has been initialized. -pub(crate) fn advance_to_block(n: BlockNumber) { - while System::block_number() < n { - Inflation::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - Inflation::on_initialize(System::block_number()); - } -} diff --git a/pallets/inflation/src/tests.rs b/pallets/inflation/src/tests.rs index db57a25cf..d41a624a3 100644 --- a/pallets/inflation/src/tests.rs +++ b/pallets/inflation/src/tests.rs @@ -78,7 +78,7 @@ fn force_set_inflation_params_fails() { fn force_set_inflation_config_work() { ExternalityBuilder::build().execute_with(|| { let mut new_config = ActiveInflationConfig::::get(); - new_config.recalculation_block = new_config.recalculation_block + 50; + new_config.recalculation_era = new_config.recalculation_era + 50; // Execute call, ensure it works assert_ok!(Inflation::force_set_inflation_config( @@ -97,7 +97,7 @@ fn force_set_inflation_config_work() { fn force_set_inflation_config_fails() { ExternalityBuilder::build().execute_with(|| { let mut new_config = ActiveInflationConfig::::get(); - new_config.recalculation_block = new_config.recalculation_block + 50; + new_config.recalculation_era = new_config.recalculation_era + 50; // Make sure action is privileged assert_noop!( @@ -113,8 +113,10 @@ fn force_inflation_recalculation_work() { let old_config = ActiveInflationConfig::::get(); // Execute call, ensure it works + let next_era = 100; assert_ok!(Inflation::force_inflation_recalculation( RuntimeOrigin::root(), + next_era, )); let new_config = ActiveInflationConfig::::get(); @@ -133,34 +135,34 @@ fn force_inflation_fails_due_to_unprivileged_origin() { ExternalityBuilder::build().execute_with(|| { // Make sure action is privileged assert_noop!( - Inflation::force_inflation_recalculation(RuntimeOrigin::signed(1)), + Inflation::force_inflation_recalculation(RuntimeOrigin::signed(1), 100), BadOrigin ); }) } #[test] -fn inflation_recalculation_occurs_when_exepcted() { +fn inflation_recalculation_occurs_when_expected() { ExternalityBuilder::build().execute_with(|| { let init_config = ActiveInflationConfig::::get(); + let recalculation_era = init_config.recalculation_era; + + // Make sure `on_finalize` calls before the expected change are storage noops - advance_to_block(init_config.recalculation_block - 3); - assert_storage_noop!(Inflation::on_finalize(init_config.recalculation_block - 3)); - Inflation::on_initialize( - init_config.recalculation_block - 2 - ); - assert_storage_noop!(Inflation::on_finalize(init_config.recalculation_block - 2)); - Inflation::on_initialize( - init_config.recalculation_block - 1 - ); + Inflation::block_before_new_era(recalculation_era - 2); + assert_storage_noop!(Inflation::on_finalize(100)); + + Inflation::block_before_new_era(recalculation_era - 1); + assert_storage_noop!(Inflation::on_finalize(200)); - // One block before recalculation, on_finalize should calculate new inflation config + // One block before recalculation era starts, on_finalize should calculate new inflation config + Inflation::block_before_new_era(recalculation_era); let init_config = ActiveInflationConfig::::get(); let init_total_issuance = Balances::total_issuance(); // Finally trigger inflation recalculation. - Inflation::on_finalize(init_config.recalculation_block - 1); + Inflation::on_finalize(300); let new_config = ActiveInflationConfig::::get(); assert_ne!( @@ -249,7 +251,7 @@ fn inflation_recalucation_works() { // Verify basics are ok assert_eq!( - new_config.recalculation_block, + new_config.recalculation_era, now + ::CycleConfiguration::blocks_per_cycle() ); assert_eq!( @@ -468,6 +470,6 @@ fn test_genesis_build() { // Verify state is as expected assert_eq!(InflationParams::::get(), genesis_config.params); - assert!(ActiveInflationConfig::::get().recalculation_block > 0); + assert!(ActiveInflationConfig::::get().recalculation_era > 0); }) } diff --git a/pallets/inflation/src/weights.rs b/pallets/inflation/src/weights.rs index 08a53283c..1fa4cfb43 100644 --- a/pallets/inflation/src/weights.rs +++ b/pallets/inflation/src/weights.rs @@ -52,8 +52,8 @@ pub trait WeightInfo { fn force_set_inflation_params() -> Weight; fn force_set_inflation_config() -> Weight; fn force_inflation_recalculation() -> Weight; - fn hook_with_recalculation() -> Weight; - fn hook_without_recalculation() -> Weight; + fn recalculation() -> Weight; + fn hooks_without_recalculation() -> Weight; } /// Weights for pallet_inflation using the Substrate node and recommended hardware. @@ -90,7 +90,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) - fn hook_with_recalculation() -> Weight { + fn recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `232` // Estimated: `6196` @@ -101,7 +101,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn hook_without_recalculation() -> Weight { + fn hooks_without_recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` @@ -145,7 +145,7 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) - fn hook_with_recalculation() -> Weight { + fn recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `232` // Estimated: `6196` @@ -156,7 +156,7 @@ impl WeightInfo for () { } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn hook_without_recalculation() -> Weight { + fn hooks_without_recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` diff --git a/primitives/src/dapp_staking.rs b/primitives/src/dapp_staking.rs index baf7ff34b..7cb8e7b0e 100644 --- a/primitives/src/dapp_staking.rs +++ b/primitives/src/dapp_staking.rs @@ -20,10 +20,19 @@ use super::{Balance, BlockNumber}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::RuntimeDebug; +use frame_support::{pallet_prelude::Weight, RuntimeDebug}; use sp_core::H160; use sp_std::hash::Hash; +/// Era number type +pub type EraNumber = u32; +/// Period number type +pub type PeriodNumber = u32; +/// Dapp Id type +pub type DAppId = u16; +/// Tier Id type +pub type TierId = u8; + /// Configuration for cycles, periods, subperiods & eras. /// /// * `cycle` - Time unit similar to 'year' in the real world. Consists of one or more periods. At the beginning of each cycle, inflation is recalculated. @@ -35,17 +44,17 @@ pub trait CycleConfiguration { /// How many different periods are there in a cycle (a 'year'). /// /// This value has to be at least 1. - fn periods_per_cycle() -> u32; + fn periods_per_cycle() -> PeriodNumber; /// For how many standard era lengths does the voting subperiod last. /// /// This value has to be at least 1. - fn eras_per_voting_subperiod() -> u32; + fn eras_per_voting_subperiod() -> EraNumber; /// How many standard eras are there in the build&earn subperiod. /// /// This value has to be at least 1. - fn eras_per_build_and_earn_subperiod() -> u32; + fn eras_per_build_and_earn_subperiod() -> EraNumber; /// How many blocks are there per standard era. /// @@ -53,12 +62,12 @@ pub trait CycleConfiguration { fn blocks_per_era() -> BlockNumber; /// For how many standard era lengths does the period last. - fn eras_per_period() -> u32 { + fn eras_per_period() -> EraNumber { Self::eras_per_voting_subperiod().saturating_add(Self::eras_per_build_and_earn_subperiod()) } - /// For how many standard era lengths does the cylce (a 'year') last. - fn eras_per_cycle() -> u32 { + /// For how many standard era lengths does the cycle (a 'year') last. + fn eras_per_cycle() -> EraNumber { Self::eras_per_period().saturating_mul(Self::periods_per_cycle()) } @@ -68,11 +77,24 @@ pub trait CycleConfiguration { } /// For how many standard era lengths do all the build&earn subperiods in a cycle last. - fn build_and_earn_eras_per_cycle() -> u32 { + fn build_and_earn_eras_per_cycle() -> EraNumber { Self::eras_per_build_and_earn_subperiod().saturating_mul(Self::periods_per_cycle()) } } +/// TODO +pub trait Observer { + /// Called in the block right before the next era starts. + /// + /// Returns the weight consumed by the call. + /// + /// # Arguments + /// * `next_era` - Era number of the next era. + fn block_before_new_era(_next_era: EraNumber) -> Weight { + Weight::zero() + } +} + /// Interface for staking reward handler. /// /// Provides reward pool values for stakers - normal & bonus rewards, as well as dApp reward pool. diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 87be4ef2d..88bcdd326 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -61,7 +61,7 @@ use sp_runtime::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use astar_primitives::{ - dapp_staking::{CycleConfiguration, SmartContract}, + dapp_staking::{CycleConfiguration, DAppId, EraNumber, PeriodNumber, SmartContract, TierId}, evm::{EvmRevertCodeHandler, HashedDefaultMappings}, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, }; @@ -514,6 +514,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type NativePriceProvider = StaticPriceProvider; type StakingRewardHandler = Inflation; type CycleConfiguration = InflationCycleConfig; + type Observers = Inflation; type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<100>; @@ -541,15 +542,15 @@ impl pallet_inflation::PayoutPerBlock for InflationPayoutPerB pub struct InflationCycleConfig; impl CycleConfiguration for InflationCycleConfig { - fn periods_per_cycle() -> u32 { + fn periods_per_cycle() -> PeriodNumber { 4 } - fn eras_per_voting_subperiod() -> u32 { + fn eras_per_voting_subperiod() -> EraNumber { 2 } - fn eras_per_build_and_earn_subperiod() -> u32 { + fn eras_per_build_and_earn_subperiod() -> EraNumber { 22 } @@ -962,13 +963,13 @@ pub enum ProxyType { Balances, /// All Runtime calls from Pallet Assets allowed for proxy account Assets, - /// Only Runtime Calls related to goverance for proxy account + /// Only Runtime Calls related to governance for proxy account /// To know exact calls check InstanceFilter implementation for ProxyTypes Governance, /// Only reject_announcement call from pallet proxy allowed for proxy account CancelProxy, /// All runtime calls from pallet DappStaking allowed for proxy account - DappsStaking, + DappStaking, /// Only claim_staker call from pallet DappStaking allowed for proxy account StakerRewardClaim, } @@ -1036,13 +1037,15 @@ impl InstanceFilter for ProxyType { ) } // All runtime calls from pallet DappStaking allowed for proxy account - ProxyType::DappsStaking => { - matches!(c, RuntimeCall::DappsStaking(..)) + ProxyType::DappStaking => { + matches!(c, RuntimeCall::DappStaking(..)) } ProxyType::StakerRewardClaim => { matches!( c, - RuntimeCall::DappsStaking(pallet_dapps_staking::Call::claim_staker { .. }) + RuntimeCall::DappStaking( + pallet_dapp_staking_v3::Call::claim_staker_rewards { .. } + ) ) } } @@ -1054,7 +1057,7 @@ impl InstanceFilter for ProxyType { (ProxyType::Any, _) => true, (_, ProxyType::Any) => false, (ProxyType::NonTransfer, _) => true, - (ProxyType::DappsStaking, ProxyType::StakerRewardClaim) => true, + (ProxyType::DappStaking, ProxyType::StakerRewardClaim) => true, _ => false, } } @@ -1728,15 +1731,15 @@ impl_runtime_apis! { } impl dapp_staking_v3_runtime_api::DappStakingApi for Runtime { - fn periods_per_cycle() -> pallet_dapp_staking_v3::PeriodNumber { + fn periods_per_cycle() -> PeriodNumber { InflationCycleConfig::periods_per_cycle() } - fn eras_per_voting_subperiod() -> pallet_dapp_staking_v3::EraNumber { + fn eras_per_voting_subperiod() -> EraNumber { InflationCycleConfig::eras_per_voting_subperiod() } - fn eras_per_build_and_earn_subperiod() -> pallet_dapp_staking_v3::EraNumber { + fn eras_per_build_and_earn_subperiod() -> EraNumber { InflationCycleConfig::eras_per_build_and_earn_subperiod() } @@ -1744,7 +1747,7 @@ impl_runtime_apis! { InflationCycleConfig::blocks_per_era() } - fn get_dapp_tier_assignment() -> BTreeMap { + fn get_dapp_tier_assignment() -> BTreeMap { DappStaking::get_dapp_tier_assignment() } } diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 0955c6364..553a10b5b 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -68,13 +68,13 @@ use sp_runtime::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use astar_primitives::{ - dapp_staking::{CycleConfiguration, SmartContract}, + dapp_staking::{CycleConfiguration, DAppId, EraNumber, PeriodNumber, SmartContract, TierId}, evm::{EvmRevertCodeHandler, HashedDefaultMappings}, xcm::AssetLocationIdConverter, Address, AssetId, BlockNumber, Hash, Header, Index, }; - pub use astar_primitives::{AccountId, Balance, Signature}; + pub use pallet_dapp_staking_v3::TierThreshold; pub use pallet_inflation::InflationParameters; @@ -447,6 +447,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type NativePriceProvider = StaticPriceProvider; type StakingRewardHandler = Inflation; type CycleConfiguration = InflationCycleConfig; + type Observers = Inflation; type EraRewardSpanLength = ConstU32<16>; type RewardRetentionInPeriods = ConstU32<2>; // Low enough value so we can get some expired rewards during testing type MaxNumberOfContracts = ConstU32<500>; @@ -474,15 +475,15 @@ impl pallet_inflation::PayoutPerBlock for InflationPayoutPerB pub struct InflationCycleConfig; impl CycleConfiguration for InflationCycleConfig { - fn periods_per_cycle() -> u32 { + fn periods_per_cycle() -> PeriodNumber { 2 } - fn eras_per_voting_subperiod() -> u32 { + fn eras_per_voting_subperiod() -> EraNumber { 8 } - fn eras_per_build_and_earn_subperiod() -> u32 { + fn eras_per_build_and_earn_subperiod() -> EraNumber { 20 } @@ -1932,15 +1933,15 @@ impl_runtime_apis! { } impl dapp_staking_v3_runtime_api::DappStakingApi for Runtime { - fn periods_per_cycle() -> pallet_dapp_staking_v3::PeriodNumber { + fn periods_per_cycle() -> PeriodNumber { InflationCycleConfig::periods_per_cycle() } - fn eras_per_voting_subperiod() -> pallet_dapp_staking_v3::EraNumber { + fn eras_per_voting_subperiod() -> EraNumber { InflationCycleConfig::eras_per_voting_subperiod() } - fn eras_per_build_and_earn_subperiod() -> pallet_dapp_staking_v3::EraNumber { + fn eras_per_build_and_earn_subperiod() -> EraNumber { InflationCycleConfig::eras_per_build_and_earn_subperiod() } @@ -1948,7 +1949,7 @@ impl_runtime_apis! { InflationCycleConfig::blocks_per_era() } - fn get_dapp_tier_assignment() -> BTreeMap { + fn get_dapp_tier_assignment() -> BTreeMap { DappStaking::get_dapp_tier_assignment() } } diff --git a/runtime/shibuya/src/weights/pallet_inflation.rs b/runtime/shibuya/src/weights/pallet_inflation.rs index 98616cb74..8a048bf35 100644 --- a/runtime/shibuya/src/weights/pallet_inflation.rs +++ b/runtime/shibuya/src/weights/pallet_inflation.rs @@ -82,7 +82,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) - fn hook_with_recalculation() -> Weight { + fn recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `232` // Estimated: `6196` @@ -93,7 +93,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn hook_without_recalculation() -> Weight { + fn hooks_without_recalculation() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` From b39bd502e67d32883e7344dc438e38adf29adc2f Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 12 Jan 2024 11:28:05 +0100 Subject: [PATCH 07/16] dApp staking modificiations --- Cargo.lock | 1 + pallets/dapp-staking-v3/src/lib.rs | 6 ++ pallets/dapp-staking-v3/src/test/tests.rs | 69 ++++++++++++++----- pallets/inflation/src/lib.rs | 14 ---- precompiles/dapp-staking-v3/src/test/mock.rs | 7 +- .../dapp-staking-v3/src/test/tests_v2.rs | 3 +- .../dapp-staking-v3/src/test/tests_v3.rs | 7 +- primitives/src/dapp_staking.rs | 4 +- tests/integration/Cargo.toml | 1 + tests/integration/src/setup.rs | 9 ++- 10 files changed, 84 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 478f34c7f..a59ba2c66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4972,6 +4972,7 @@ dependencies = [ "pallet-evm", "pallet-evm-precompile-assets-erc20", "pallet-evm-precompile-dispatch", + "pallet-inflation", "pallet-proxy", "pallet-unified-accounts", "pallet-utility", diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 6d8c6260f..89100afca 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1793,6 +1793,12 @@ pub mod pallet { return consumed_weight; } + // Inform observers about the upcoming new era, if it's the case. + if protocol_state.next_era_start == now.saturating_add(1) { + let next_era = protocol_state.era.saturating_add(1); + consumed_weight.saturating_accrue(T::Observers::block_before_new_era(next_era)); + } + // Nothing to do if it's not new era if !protocol_state.is_new_era(now) { return consumed_weight; diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index e3fae0dda..c473edee6 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -30,12 +30,12 @@ use frame_support::{ use sp_runtime::traits::Zero; use astar_primitives::{ - dapp_staking::{CycleConfiguration, SmartContractHandle}, + dapp_staking::{CycleConfiguration, EraNumber, SmartContractHandle}, Balance, BlockNumber, }; #[test] -fn maintenace_mode_works() { +fn maintenances_mode_works() { ExtBuilder::build().execute_with(|| { // Check that maintenance mode is disabled by default assert!(!ActiveProtocolState::::get().maintenance); @@ -63,7 +63,7 @@ fn maintenace_mode_works() { } #[test] -fn maintenace_mode_call_filtering_works() { +fn maintenance_mode_call_filtering_works() { ExtBuilder::build().execute_with(|| { // Enable maintenance mode & check post-state assert_ok!(DappStaking::maintenance_mode(RuntimeOrigin::root(), true)); @@ -237,7 +237,7 @@ fn on_initialize_base_state_change_works() { assert_eq!(protocol_state.era, era + 1); } - // Finaly advance over to the next era and ensure we're back to voting period + // Finally advance over to the next era and ensure we're back to voting period advance_to_next_era(); let protocol_state = ActiveProtocolState::::get(); assert_eq!(protocol_state.subperiod(), Subperiod::Voting); @@ -356,7 +356,7 @@ fn set_dapp_reward_beneficiary_fails() { Error::::ContractNotFound ); - // Non-owner cannnot change reward destination + // Non-owner cannot change reward destination assert_register(owner, &smart_contract); assert_noop!( DappStaking::set_dapp_reward_beneficiary( @@ -582,7 +582,7 @@ fn unlock_with_remaining_amount_below_threshold_is_ok() { } #[test] -fn unlock_with_amount_higher_than_avaiable_is_ok() { +fn unlock_with_amount_higher_than_available_is_ok() { ExtBuilder::build().execute_with(|| { // Lock some amount in a few eras let account = 2; @@ -720,7 +720,7 @@ fn unlock_with_exceeding_unlocking_chunks_storage_limits_fails() { #[test] fn withdraw_unbonded_is_ok() { ExtBuilder::build().execute_with(|| { - // Lock & immediatelly unlock some amount + // Lock & immediately unlock some amount let account = 2; let lock_amount = 97; let unlock_amount = 11; @@ -1523,7 +1523,7 @@ fn claim_staker_rewards_fails_due_to_payout_failure() { // Advance into Build&Earn period, and allow one era to pass. advance_to_era(ActiveProtocolState::::get().era + 2); - // Disable successfull reward payout + // Disable successful reward payout DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); assert_noop!( DappStaking::claim_staker_rewards(RuntimeOrigin::signed(account)), @@ -1705,7 +1705,7 @@ fn claim_bonus_reward_fails_due_to_payout_failure() { // Advance to next period so we can claim bonus reward advance_to_next_period(); - // Disable successfull reward payout + // Disable successful reward payout DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); assert_noop!( DappStaking::claim_bonus_reward(RuntimeOrigin::signed(account), smart_contract), @@ -1904,7 +1904,7 @@ fn claim_dapp_reward_fails_due_to_payout_failure() { // Advance 2 eras so we have an entry for reward claiming advance_to_era(ActiveProtocolState::::get().era + 2); - // Disable successfull reward payout + // Disable successful reward payout DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); assert_noop!( DappStaking::claim_dapp_reward( @@ -2438,11 +2438,6 @@ fn advance_for_some_periods_works() { }) } -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// -/////// More complex & composite scenarios, maybe move them into a separate file - #[test] fn unlock_after_staked_period_ends_is_ok() { ExtBuilder::build().execute_with(|| { @@ -2571,7 +2566,7 @@ fn stake_after_period_ends_with_max_staked_contracts() { } #[test] -fn post_unlock_balance_cannot_be_transfered() { +fn post_unlock_balance_cannot_be_transferred() { ExtBuilder::build().execute_with(|| { let staker = 2; @@ -2628,3 +2623,45 @@ fn post_unlock_balance_cannot_be_transfered() { assert!(Balances::free_balance(&staker).is_zero()); }) } + +#[test] +fn observer_pre_new_era_block_works() { + ExtBuilder::build().execute_with(|| { + fn assert_observer_value(expected: EraNumber) { + BLOCK_BEFORE_NEW_ERA.with(|v| assert_eq!(expected, *v.borrow())); + } + + // 1. Sanity check + assert_observer_value(0); + + // 2. Advance to the block right before the observer value should be set. + // No modifications should happen. + BLOCK_BEFORE_NEW_ERA.with(|v| { + let _lock = v.borrow(); + run_to_block(ActiveProtocolState::::get().next_era_start - 2); + }); + + // 3. Advance to the next block, when observer value is expected to be set to the next era. + run_for_blocks(1); + assert_observer_value(2); + + // 4. Advance again, until the same similar scenario + BLOCK_BEFORE_NEW_ERA.with(|v| { + let _lock = v.borrow(); + run_for_blocks(1); + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn, + "Sanity check." + ); + + run_to_block(ActiveProtocolState::::get().next_era_start - 2); + assert_eq!(ActiveProtocolState::::get().era, 2, "Sanity check."); + assert_observer_value(2); + }); + + // 5. Again, check that value is set to the expected one. + run_for_blocks(1); + assert_observer_value(3); + }) +} diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 97565825e..1ecd7f405 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -322,20 +322,6 @@ pub mod pallet { } impl Pallet { - /// Informs the pallet that the next block will be the first block of a new era. - // TODO: make an interface for this - pub fn block_before_new_era(new_era: EraNumber) -> Weight { - let config = ActiveInflationConfig::::get(); - if config.recalculation_era <= new_era { - DoRecalculation::::put(new_era); - - // Need to account for write into a single whitelisted storage item. - T::WeightInfo::recalculation().saturating_add(T::DbWeight::get().writes(1)) - } else { - Weight::zero() - } - } - /// Payout block rewards to the beneficiaries. /// /// Return the total amount issued. diff --git a/precompiles/dapp-staking-v3/src/test/mock.rs b/precompiles/dapp-staking-v3/src/test/mock.rs index feff4d634..36359b945 100644 --- a/precompiles/dapp-staking-v3/src/test/mock.rs +++ b/precompiles/dapp-staking-v3/src/test/mock.rs @@ -38,12 +38,14 @@ use sp_runtime::traits::{BlakeTwo256, ConstU32, IdentityLookup}; extern crate alloc; use astar_primitives::{ - dapp_staking::{CycleConfiguration, SmartContract, StakingRewardHandler}, + dapp_staking::{ + CycleConfiguration, EraNumber, PeriodNumber, SmartContract, StakingRewardHandler, + }, oracle::PriceProvider, testing::Header, AccountId, Balance, BlockNumber, }; -use pallet_dapp_staking_v3::{EraNumber, PeriodNumber, TierThreshold}; +use pallet_dapp_staking_v3::TierThreshold; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -249,6 +251,7 @@ impl pallet_dapp_staking_v3::Config for Test { type NativePriceProvider = DummyPriceProvider; type StakingRewardHandler = DummyStakingRewardHandler; type CycleConfiguration = DummyCycleConfiguration; + type Observers = (); type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<10>; diff --git a/precompiles/dapp-staking-v3/src/test/tests_v2.rs b/precompiles/dapp-staking-v3/src/test/tests_v2.rs index 8d93b5619..2279b97fb 100644 --- a/precompiles/dapp-staking-v3/src/test/tests_v2.rs +++ b/precompiles/dapp-staking-v3/src/test/tests_v2.rs @@ -26,7 +26,8 @@ use sp_runtime::traits::Zero; use assert_matches::assert_matches; -use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber, EraRewards}; +use astar_primitives::dapp_staking::EraNumber; +use pallet_dapp_staking_v3::{ActiveProtocolState, EraRewards}; #[test] fn read_current_era_is_ok() { diff --git a/precompiles/dapp-staking-v3/src/test/tests_v3.rs b/precompiles/dapp-staking-v3/src/test/tests_v3.rs index 5977417b5..2ab48e45b 100644 --- a/precompiles/dapp-staking-v3/src/test/tests_v3.rs +++ b/precompiles/dapp-staking-v3/src/test/tests_v3.rs @@ -25,8 +25,11 @@ use sp_core::H160; use assert_matches::assert_matches; -use astar_primitives::{dapp_staking::CycleConfiguration, BlockNumber}; -use pallet_dapp_staking_v3::{ActiveProtocolState, EraNumber}; +use astar_primitives::{ + dapp_staking::{CycleConfiguration, EraNumber}, + BlockNumber, +}; +use pallet_dapp_staking_v3::ActiveProtocolState; #[test] fn protocol_state_is_ok() { diff --git a/primitives/src/dapp_staking.rs b/primitives/src/dapp_staking.rs index 7cb8e7b0e..ee6eeedfa 100644 --- a/primitives/src/dapp_staking.rs +++ b/primitives/src/dapp_staking.rs @@ -82,7 +82,7 @@ pub trait CycleConfiguration { } } -/// TODO +/// Trait for observers (listeners) of various events related to dApp staking protocol. pub trait Observer { /// Called in the block right before the next era starts. /// @@ -95,6 +95,8 @@ pub trait Observer { } } +impl Observer for () {} + /// Interface for staking reward handler. /// /// Provides reward pool values for stakers - normal & bonus rewards, as well as dApp reward pool. diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index 5bb0a1971..e32a4d3cc 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -27,6 +27,7 @@ pallet-contracts = { workspace = true } pallet-contracts-primitives = { workspace = true } pallet-dapp-staking-v3 = { workspace = true } pallet-dapps-staking = { workspace = true } +pallet-inflation = { workspace = true } pallet-proxy = { workspace = true } pallet-utility = { workspace = true } sp-core = { workspace = true } diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index ba266bfe3..9ac4664d6 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -20,7 +20,7 @@ pub use frame_support::{ assert_noop, assert_ok, - traits::{OnFinalize, OnIdle, OnInitialize}, + traits::{GenesisBuild, OnFinalize, OnIdle, OnInitialize}, weights::Weight, }; pub use pallet_evm::AddressMapping; @@ -191,6 +191,13 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); + // Needed to trigger initial inflation config setting. + >::assimilate_storage( + &pallet_inflation::GenesisConfig::default(), + &mut t, + ) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext From 8c364cb4809db642d9af4aef5e3f038d0f5292c1 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 12 Jan 2024 11:53:38 +0100 Subject: [PATCH 08/16] Fix tests --- tests/integration/src/setup.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 9ac4664d6..66a4c89a7 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -191,6 +191,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); + #[cfg(any(feature = "shibuya"))] // Needed to trigger initial inflation config setting. >::assimilate_storage( &pallet_inflation::GenesisConfig::default(), From 0ee87393a2cc29c3c84d891accc43ae6f246ee8d Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 12 Jan 2024 16:15:50 +0100 Subject: [PATCH 09/16] Migration logic --- pallets/dapp-staking-v3/src/lib.rs | 21 ++++++---- pallets/dapp-staking-v3/src/test/tests.rs | 6 +++ pallets/inflation/src/lib.rs | 16 +++++++- runtime/shibuya/src/lib.rs | 49 +++++++++++++++++++++++ 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 89100afca..64872d64f 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1496,16 +1496,11 @@ pub mod pallet { .into()) } - // TODO: this call should be removed prior to mainnet launch. - // It's super useful for testing purposes, but even though force is used in this pallet & works well, - // it won't apply to the inflation recalculation logic - which is wrong. - // Probably for this call to make sense, an outside logic should handle both inflation & dApp staking state changes. - /// Used to force a change of era or subperiod. /// The effect isn't immediate but will happen on the next block. /// /// Used for testing purposes, when we want to force an era change, or a subperiod change. - /// Not intended to be used in production, except in case of unforseen circumstances. + /// Not intended to be used in production, except in case of unforeseen circumstances. /// /// Can only be called by manager origin. #[pallet::call_index(18)] @@ -1525,6 +1520,10 @@ pub mod pallet { state.period_info.next_subperiod_start_era = state.era.saturating_add(1); } } + + // TODO: Right now it won't account for the full weight incurred by calling this notification. + // It's not a big problem since this call is not expected to be called ever in production. + Self::notify_block_before_new_era(&state); }); Self::deposit_event(Event::::Force { forcing_type }); @@ -1795,8 +1794,8 @@ pub mod pallet { // Inform observers about the upcoming new era, if it's the case. if protocol_state.next_era_start == now.saturating_add(1) { - let next_era = protocol_state.era.saturating_add(1); - consumed_weight.saturating_accrue(T::Observers::block_before_new_era(next_era)); + consumed_weight + .saturating_accrue(Self::notify_block_before_new_era(&protocol_state)); } // Nothing to do if it's not new era @@ -1955,6 +1954,12 @@ pub mod pallet { consumed_weight } + /// Used to notify observers about the upcoming new era in the next block. + fn notify_block_before_new_era(protocol_state: &ProtocolState) -> Weight { + let next_era = protocol_state.era.saturating_add(1); + T::Observers::block_before_new_era(next_era) + } + /// Attempt to cleanup some expired entries, if enough remaining weight & applicable entries exist. /// /// Returns consumed weight. diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index c473edee6..3e409379a 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -2663,5 +2663,11 @@ fn observer_pre_new_era_block_works() { // 5. Again, check that value is set to the expected one. run_for_blocks(1); assert_observer_value(3); + + // 6. Force new era, and ensure observer value is set to the next one. + run_for_blocks(1); + assert_eq!(ActiveProtocolState::::get().era, 3, "Sanity check."); + assert_ok!(DappStaking::force(RuntimeOrigin::root(), ForcingType::Era)); + assert_observer_value(4); }) } diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 1ecd7f405..0cd123d45 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -636,4 +636,18 @@ impl> OnRuntimeUpgrade } } -// TODO: add migration for Shibuya, to set proper next era +/// To be used just for Shibuya, can be removed after migration has been executed. +pub struct PalletInflationShibuyaMigration(PhantomData<(T, P)>); +impl> OnRuntimeUpgrade + for PalletInflationShibuyaMigration +{ + fn on_runtime_upgrade() -> Weight { + let (recalculation_era, weight) = P::get(); + ActiveInflationConfig::::mutate(|config| { + // Both recalculation_era and recalculation_block are of the same `u32` type so no need to do any translation. + config.recalculation_era = recalculation_era; + }); + + T::DbWeight::get().reads_writes(1, 1).saturating_add(weight) + } +} diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 553a10b5b..cada4f3b7 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -1387,8 +1387,57 @@ impl Get for InitActivePriceGet { pub type Migrations = ( pallet_static_price_provider::InitActivePrice, pallet_dapp_staking_v3::migrations::DappStakingV3TierRewardAsTree, + pallet_inflation::PalletInflationShibuyaMigration, ); +pub struct NextEraProvider; +impl Get<(EraNumber, Weight)> for NextEraProvider { + fn get() -> (EraNumber, Weight) { + // Prior to executing the migration, `recalculation_era` is still set to the old `recalculation_block` + let target_block = + pallet_inflation::ActiveInflationConfig::::get().recalculation_era; + + let state = pallet_dapp_staking_v3::ActiveProtocolState::::get(); + + // Best case scenario, the target era is the first era of the next period. + use pallet_dapp_staking_v3::Subperiod; + let mut target_era = match state.subperiod() { + Subperiod::Voting => state.era.saturating_add( + InflationCycleConfig::eras_per_build_and_earn_subperiod().saturating_add(1), + ), + Subperiod::BuildAndEarn => state.next_subperiod_start_era(), + }; + + // Adding the whole period length in blocks to the current block number, and comparing it with the target + // is good enough to find the target era. + let period_length_in_blocks = InflationCycleConfig::blocks_per_cycle() + / InflationCycleConfig::periods_per_cycle().max(1); + let mut block = System::block_number().saturating_add(period_length_in_blocks); + + // Max number of iterations is the number of periods per cycle, it's not possible for more than that to occur. + let mut limit = InflationCycleConfig::periods_per_cycle(); + + use sp_runtime::traits::Saturating; + while block < target_block && limit > 0 { + target_era.saturating_accrue(InflationCycleConfig::eras_per_period()); + block.saturating_accrue(period_length_in_blocks); + + limit.saturating_dec() + } + + #[cfg(feature = "try-runtime")] + if block < target_block { + panic!("Failed to find target era for migration, please check for errors"); + } + + // A bit overestimated weight, but it's fine since we have some calculations to execute in this function which consume some time. + ( + target_era, + ::DbWeight::get().reads(3), + ) + } +} + type EventRecord = frame_system::EventRecord< ::RuntimeEvent, ::Hash, From a43479115b39bb528be2f732f19a4f84b0b358c3 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 12 Jan 2024 17:22:36 +0100 Subject: [PATCH 10/16] integration tests --- pallets/dapp-staking-v3/src/lib.rs | 5 +- pallets/inflation/src/lib.rs | 2 +- pallets/inflation/src/tests.rs | 6 +- runtime/shibuya/src/lib.rs | 2 +- tests/integration/src/dapp_staking_v3.rs | 80 ++++++++++++++++++++++++ tests/integration/src/lib.rs | 3 + tests/integration/src/setup.rs | 8 ++- 7 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 tests/integration/src/dapp_staking_v3.rs diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 64872d64f..7525370f4 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1496,6 +1496,7 @@ pub mod pallet { .into()) } + // TODO: make this unavailable in production, to be only used for testing /// Used to force a change of era or subperiod. /// The effect isn't immediate but will happen on the next block. /// @@ -1521,8 +1522,10 @@ pub mod pallet { } } - // TODO: Right now it won't account for the full weight incurred by calling this notification. + // Right now it won't account for the full weight incurred by calling this notification. // It's not a big problem since this call is not expected to be called ever in production. + // Also, in case of subperiod forcing, the alignment will be broken but since this is only call for testing, + // we don't need to concern ourselves with it. Self::notify_block_before_new_era(&state); }); diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 0cd123d45..2361521a8 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -385,7 +385,7 @@ pub mod pallet { // 4. Block at which the inflation must be recalculated. let recalculation_era = - next_era.saturating_add(T::CycleConfiguration::blocks_per_cycle()); + next_era.saturating_add(T::CycleConfiguration::eras_per_cycle()); // 5. Return calculated values InflationConfiguration { diff --git a/pallets/inflation/src/tests.rs b/pallets/inflation/src/tests.rs index d41a624a3..75f82800e 100644 --- a/pallets/inflation/src/tests.rs +++ b/pallets/inflation/src/tests.rs @@ -239,7 +239,7 @@ fn inflation_parameters_validity_check_works() { } #[test] -fn inflation_recalucation_works() { +fn inflation_recalculation_works() { ExternalityBuilder::build().execute_with(|| { let total_issuance = Balances::total_issuance(); let params = InflationParams::::get(); @@ -252,7 +252,7 @@ fn inflation_recalucation_works() { // Verify basics are ok assert_eq!( new_config.recalculation_era, - now + ::CycleConfiguration::blocks_per_cycle() + now + ::CycleConfiguration::eras_per_cycle() ); assert_eq!( new_config.issuance_safety_cap, @@ -432,7 +432,7 @@ fn payout_reward_fails_when_relaxed_cap_is_exceeded() { } #[test] -fn cylcle_configuration_works() { +fn cycle_configuration_works() { ExternalityBuilder::build().execute_with(|| { type CycleConfig = ::CycleConfiguration; diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index cada4f3b7..34c0ae9dc 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -757,7 +757,7 @@ impl WeightToFeePolynomial for WeightToFee { } } -/// Handles coverting weight consumed by XCM into native currency fee. +/// Handles converting weight consumed by XCM into native currency fee. /// /// Similar to standard `WeightToFee` handler, but force uses the minimum multiplier. pub struct XcmWeightToFee; diff --git a/tests/integration/src/dapp_staking_v3.rs b/tests/integration/src/dapp_staking_v3.rs new file mode 100644 index 000000000..1a79c9ccb --- /dev/null +++ b/tests/integration/src/dapp_staking_v3.rs @@ -0,0 +1,80 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +#![cfg(test)] + +use crate::setup::*; + +use pallet_dapp_staking_v3::*; + +#[test] +fn dapp_staking_triggers_inflation_recalculation() { + new_test_ext().execute_with(|| { + let init_inflation_config = pallet_inflation::ActiveInflationConfig::::get(); + + let recalculation_era = init_inflation_config.recalculation_era; + + // It's not feasible to run through all the blocks needed to trigger all the eras. + // Instead, we force the era to change on a block by block basis. + while ActiveProtocolState::::get().era < recalculation_era - 1 { + assert_ok!(DappStaking::force(RuntimeOrigin::root(), ForcingType::Era,)); + run_for_blocks(1); + assert_eq!( + init_inflation_config, + pallet_inflation::ActiveInflationConfig::::get(), + "Must not change until recalculation" + ); + } + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn, + "Sanity check." + ); + + // Again, hacky approach to speed things up. + // This doesn't influence anything in the protocol essentially. + ActiveProtocolState::::mutate(|state| { + state.next_era_start = System::block_number() + 5; + }); + + // Another sanity check, move block by block and ensure protocol works as expected. + let target_block = ActiveProtocolState::::get().next_era_start; + run_to_block(target_block - 2); + assert_eq!( + init_inflation_config, + pallet_inflation::ActiveInflationConfig::::get(), + "Sanity check." + ); + + // So far inflation config remained unchanged. + // Now we expect the trigger which will update it. + run_for_blocks(1); + assert_eq!( + init_inflation_config, + pallet_inflation::ActiveInflationConfig::::get(), + "Still the same, should be updated ONLY after the block has been finalized." + ); + + run_for_blocks(1); + let new_inflation_config = pallet_inflation::ActiveInflationConfig::::get(); + assert_ne!( + init_inflation_config, new_inflation_config, + "Must be updated after the block has been finalized." + ); + }); +} diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index 43b2d9843..50023a9f5 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -45,3 +45,6 @@ mod dispatch_precompile_filter_old; #[cfg(feature = "shibuya")] mod unified_accounts; + +#[cfg(feature = "shibuya")] +mod dapp_staking_v3; diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 66a4c89a7..5ce81c65d 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -28,7 +28,7 @@ pub use sp_core::{H160, H256, U256}; pub use sp_io::hashing::keccak_256; pub use sp_runtime::{AccountId32, MultiAddress}; -pub use astar_primitives::evm::UnifiedAddressMapper; +pub use astar_primitives::{evm::UnifiedAddressMapper, BlockNumber}; #[cfg(feature = "shibuya")] pub use shibuya::*; @@ -218,7 +218,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Block time: 12 seconds. pub const BLOCK_TIME: u64 = 12_000; -pub fn run_to_block(n: u32) { +pub fn run_to_block(n: BlockNumber) { while System::block_number() < n { let block_number = System::block_number(); TransactionPayment::on_finalize(block_number); @@ -260,6 +260,10 @@ pub fn run_to_block(n: u32) { } } +pub fn run_for_blocks(n: BlockNumber) { + run_to_block(System::block_number() + n) +} + fn last_events(n: usize) -> Vec { frame_system::Pallet::::events() .into_iter() From 6343c676293c0d1d22cc6a7e0b277bc5f408ae40 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 15 Jan 2024 14:34:41 +0100 Subject: [PATCH 11/16] Changes,updated weights --- pallets/dapp-staking-v3/src/weights.rs | 252 +++++++++--------- pallets/inflation/src/lib.rs | 4 +- pallets/inflation/src/weights.rs | 66 +++-- pallets/static-price-provider/src/lib.rs | 6 +- .../src/weights/pallet_dapp_staking_v3.rs | 124 ++++----- .../shibuya/src/weights/pallet_inflation.rs | 31 +-- 6 files changed, 239 insertions(+), 244 deletions(-) diff --git a/pallets/dapp-staking-v3/src/weights.rs b/pallets/dapp-staking-v3/src/weights.rs index e98d79870..8c5c926f3 100644 --- a/pallets/dapp-staking-v3/src/weights.rs +++ b/pallets/dapp-staking-v3/src/weights.rs @@ -20,9 +20,9 @@ //! Autogenerated weights for pallet_dapp_staking_v3 //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-01-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` +//! HOSTNAME: `gh-runner-01-ovh`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 // Executed Command: @@ -81,8 +81,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_474_000 picoseconds. - Weight::from_parts(8_711_000, 0) + // Minimum execution time: 9_265_000 picoseconds. + Weight::from_parts(9_422_000, 0) } /// Storage: DappStaking IntegratedDApps (r:1 w:1) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) @@ -94,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3091` - // Minimum execution time: 16_360_000 picoseconds. - Weight::from_parts(16_697_000, 3091) + // Minimum execution time: 17_285_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -105,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 12_927_000 picoseconds. - Weight::from_parts(13_229_000, 3091) + // Minimum execution time: 13_521_000 picoseconds. + Weight::from_parts(13_819_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,8 +116,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 13_610_000 picoseconds. - Weight::from_parts(13_851_000, 3091) + // Minimum execution time: 13_797_000 picoseconds. + Weight::from_parts(14_051_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -129,8 +129,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 16_704_000 picoseconds. - Weight::from_parts(16_952_000, 3091) + // Minimum execution time: 17_242_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `12` // Estimated: `4764` - // Minimum execution time: 31_680_000 picoseconds. - Weight::from_parts(32_075_000, 4764) + // Minimum execution time: 32_138_000 picoseconds. + Weight::from_parts(32_677_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -163,8 +163,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `156` // Estimated: `4764` - // Minimum execution time: 34_576_000 picoseconds. - Weight::from_parts(34_777_000, 4764) + // Minimum execution time: 33_789_000 picoseconds. + Weight::from_parts(34_052_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -181,10 +181,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `187` // Estimated: `4764` - // Minimum execution time: 33_562_000 picoseconds. - Weight::from_parts(34_600_552, 4764) - // Standard Error: 5_079 - .saturating_add(Weight::from_parts(193_345, 0).saturating_mul(x.into())) + // Minimum execution time: 35_048_000 picoseconds. + Weight::from_parts(36_286_241, 4764) + // Standard Error: 6_246 + .saturating_add(Weight::from_parts(176_805, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -200,8 +200,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `182` // Estimated: `4764` - // Minimum execution time: 36_436_000 picoseconds. - Weight::from_parts(37_262_000, 4764) + // Minimum execution time: 30_390_000 picoseconds. + Weight::from_parts(30_712_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -223,8 +223,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `4764` - // Minimum execution time: 43_866_000 picoseconds. - Weight::from_parts(44_468_000, 4764) + // Minimum execution time: 44_866_000 picoseconds. + Weight::from_parts(45_342_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -246,8 +246,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `427` // Estimated: `4764` - // Minimum execution time: 47_368_000 picoseconds. - Weight::from_parts(48_049_000, 4764) + // Minimum execution time: 48_475_000 picoseconds. + Weight::from_parts(49_000_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -266,10 +266,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `560` // Estimated: `4764` - // Minimum execution time: 51_230_000 picoseconds. - Weight::from_parts(48_696_805, 4764) - // Standard Error: 6_139 - .saturating_add(Weight::from_parts(3_374_191, 0).saturating_mul(x.into())) + // Minimum execution time: 51_987_000 picoseconds. + Weight::from_parts(49_569_909, 4764) + // Standard Error: 5_547 + .saturating_add(Weight::from_parts(3_433_220, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -286,10 +286,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `501` // Estimated: `4764` - // Minimum execution time: 45_030_000 picoseconds. - Weight::from_parts(43_179_071, 4764) - // Standard Error: 5_547 - .saturating_add(Weight::from_parts(3_296_864, 0).saturating_mul(x.into())) + // Minimum execution time: 48_592_000 picoseconds. + Weight::from_parts(46_136_422, 4764) + // Standard Error: 4_476 + .saturating_add(Weight::from_parts(3_444_512, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -303,21 +303,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3775` - // Minimum execution time: 42_248_000 picoseconds. - Weight::from_parts(42_687_000, 3775) + // Minimum execution time: 38_973_000 picoseconds. + Weight::from_parts(39_533_000, 3775) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: DappStaking IntegratedDApps (r:1 w:0) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:1 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn claim_dapp_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `3021` - // Estimated: `5548` - // Minimum execution time: 50_968_000 picoseconds. - Weight::from_parts(51_778_000, 5548) + // Measured: `2585` + // Estimated: `5048` + // Minimum execution time: 54_909_000 picoseconds. + Weight::from_parts(55_839_000, 5048) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -337,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `389` // Estimated: `4764` - // Minimum execution time: 42_329_000 picoseconds. - Weight::from_parts(42_737_000, 4764) + // Minimum execution time: 42_755_000 picoseconds. + Weight::from_parts(43_230_000, 4764) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -355,10 +355,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255 + x * (69 ±0)` // Estimated: `4764 + x * (2613 ±0)` - // Minimum execution time: 42_222_000 picoseconds. - Weight::from_parts(38_945_386, 4764) - // Standard Error: 14_325 - .saturating_add(Weight::from_parts(5_044_310, 0).saturating_mul(x.into())) + // Minimum execution time: 39_922_000 picoseconds. + Weight::from_parts(36_255_858, 4764) + // Standard Error: 14_366 + .saturating_add(Weight::from_parts(5_135_083, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -369,8 +369,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_971_000 picoseconds. - Weight::from_parts(10_190_000, 0) + // Minimum execution time: 11_519_000 picoseconds. + Weight::from_parts(11_865_000, 0) } /// Storage: DappStaking CurrentEraInfo (r:1 w:1) /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) @@ -380,8 +380,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16` // Estimated: `4254` - // Minimum execution time: 17_308_000 picoseconds. - Weight::from_parts(17_774_000, 4254) + // Minimum execution time: 17_823_000 picoseconds. + Weight::from_parts(18_413_000, 4254) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -396,13 +396,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking PeriodEnd (r:0 w:1) /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_voting() -> Weight { // Proof Size summary in bytes: // Measured: `550` // Estimated: `4254` - // Minimum execution time: 39_768_000 picoseconds. - Weight::from_parts(40_422_000, 4254) + // Minimum execution time: 41_147_000 picoseconds. + Weight::from_parts(42_304_000, 4254) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -411,13 +411,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_build_and_earn() -> Weight { // Proof Size summary in bytes: // Measured: `68` // Estimated: `4254` - // Minimum execution time: 20_976_000 picoseconds. - Weight::from_parts(21_507_000, 4254) + // Minimum execution time: 23_807_000 picoseconds. + Weight::from_parts(24_367_000, 4254) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -430,10 +430,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `152 + x * (32 ±0)` // Estimated: `3061 + x * (2071 ±0)` - // Minimum execution time: 7_374_000 picoseconds. - Weight::from_parts(10_826_637, 3061) - // Standard Error: 3_374 - .saturating_add(Weight::from_parts(2_291_643, 0).saturating_mul(x.into())) + // Minimum execution time: 7_821_000 picoseconds. + Weight::from_parts(12_000_144, 3061) + // Standard Error: 3_553 + .saturating_add(Weight::from_parts(2_396_421, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(Weight::from_parts(0, 2071).saturating_mul(x.into())) @@ -445,13 +445,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_idle_cleanup() -> Weight { // Proof Size summary in bytes: // Measured: `473` // Estimated: `4254` - // Minimum execution time: 14_500_000 picoseconds. - Weight::from_parts(14_969_000, 4254) + // Minimum execution time: 17_154_000 picoseconds. + Weight::from_parts(17_535_000, 4254) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -463,8 +463,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_474_000 picoseconds. - Weight::from_parts(8_711_000, 0) + // Minimum execution time: 9_265_000 picoseconds. + Weight::from_parts(9_422_000, 0) } /// Storage: DappStaking IntegratedDApps (r:1 w:1) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) @@ -476,8 +476,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3091` - // Minimum execution time: 16_360_000 picoseconds. - Weight::from_parts(16_697_000, 3091) + // Minimum execution time: 17_285_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -487,8 +487,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 12_927_000 picoseconds. - Weight::from_parts(13_229_000, 3091) + // Minimum execution time: 13_521_000 picoseconds. + Weight::from_parts(13_819_000, 3091) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -498,8 +498,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 13_610_000 picoseconds. - Weight::from_parts(13_851_000, 3091) + // Minimum execution time: 13_797_000 picoseconds. + Weight::from_parts(14_051_000, 3091) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -511,8 +511,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 16_704_000 picoseconds. - Weight::from_parts(16_952_000, 3091) + // Minimum execution time: 17_242_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -528,8 +528,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `12` // Estimated: `4764` - // Minimum execution time: 31_680_000 picoseconds. - Weight::from_parts(32_075_000, 4764) + // Minimum execution time: 32_138_000 picoseconds. + Weight::from_parts(32_677_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -545,8 +545,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `156` // Estimated: `4764` - // Minimum execution time: 34_576_000 picoseconds. - Weight::from_parts(34_777_000, 4764) + // Minimum execution time: 33_789_000 picoseconds. + Weight::from_parts(34_052_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -563,10 +563,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `187` // Estimated: `4764` - // Minimum execution time: 33_562_000 picoseconds. - Weight::from_parts(34_600_552, 4764) - // Standard Error: 5_079 - .saturating_add(Weight::from_parts(193_345, 0).saturating_mul(x.into())) + // Minimum execution time: 35_048_000 picoseconds. + Weight::from_parts(36_286_241, 4764) + // Standard Error: 6_246 + .saturating_add(Weight::from_parts(176_805, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -582,8 +582,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `182` // Estimated: `4764` - // Minimum execution time: 36_436_000 picoseconds. - Weight::from_parts(37_262_000, 4764) + // Minimum execution time: 30_390_000 picoseconds. + Weight::from_parts(30_712_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -605,8 +605,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250` // Estimated: `4764` - // Minimum execution time: 43_866_000 picoseconds. - Weight::from_parts(44_468_000, 4764) + // Minimum execution time: 44_866_000 picoseconds. + Weight::from_parts(45_342_000, 4764) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -628,8 +628,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `427` // Estimated: `4764` - // Minimum execution time: 47_368_000 picoseconds. - Weight::from_parts(48_049_000, 4764) + // Minimum execution time: 48_475_000 picoseconds. + Weight::from_parts(49_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -648,10 +648,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `560` // Estimated: `4764` - // Minimum execution time: 51_230_000 picoseconds. - Weight::from_parts(48_696_805, 4764) - // Standard Error: 6_139 - .saturating_add(Weight::from_parts(3_374_191, 0).saturating_mul(x.into())) + // Minimum execution time: 51_987_000 picoseconds. + Weight::from_parts(49_569_909, 4764) + // Standard Error: 5_547 + .saturating_add(Weight::from_parts(3_433_220, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -668,10 +668,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `501` // Estimated: `4764` - // Minimum execution time: 45_030_000 picoseconds. - Weight::from_parts(43_179_071, 4764) - // Standard Error: 5_547 - .saturating_add(Weight::from_parts(3_296_864, 0).saturating_mul(x.into())) + // Minimum execution time: 48_592_000 picoseconds. + Weight::from_parts(46_136_422, 4764) + // Standard Error: 4_476 + .saturating_add(Weight::from_parts(3_444_512, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -685,21 +685,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3775` - // Minimum execution time: 42_248_000 picoseconds. - Weight::from_parts(42_687_000, 3775) + // Minimum execution time: 38_973_000 picoseconds. + Weight::from_parts(39_533_000, 3775) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: DappStaking IntegratedDApps (r:1 w:0) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:1 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn claim_dapp_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `3021` - // Estimated: `5548` - // Minimum execution time: 50_968_000 picoseconds. - Weight::from_parts(51_778_000, 5548) + // Measured: `2585` + // Estimated: `5048` + // Minimum execution time: 54_909_000 picoseconds. + Weight::from_parts(55_839_000, 5048) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -719,8 +719,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `389` // Estimated: `4764` - // Minimum execution time: 42_329_000 picoseconds. - Weight::from_parts(42_737_000, 4764) + // Minimum execution time: 42_755_000 picoseconds. + Weight::from_parts(43_230_000, 4764) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -737,10 +737,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `255 + x * (69 ±0)` // Estimated: `4764 + x * (2613 ±0)` - // Minimum execution time: 42_222_000 picoseconds. - Weight::from_parts(38_945_386, 4764) - // Standard Error: 14_325 - .saturating_add(Weight::from_parts(5_044_310, 0).saturating_mul(x.into())) + // Minimum execution time: 39_922_000 picoseconds. + Weight::from_parts(36_255_858, 4764) + // Standard Error: 14_366 + .saturating_add(Weight::from_parts(5_135_083, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -751,8 +751,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_971_000 picoseconds. - Weight::from_parts(10_190_000, 0) + // Minimum execution time: 11_519_000 picoseconds. + Weight::from_parts(11_865_000, 0) } /// Storage: DappStaking CurrentEraInfo (r:1 w:1) /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) @@ -762,8 +762,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16` // Estimated: `4254` - // Minimum execution time: 17_308_000 picoseconds. - Weight::from_parts(17_774_000, 4254) + // Minimum execution time: 17_823_000 picoseconds. + Weight::from_parts(18_413_000, 4254) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -778,13 +778,13 @@ impl WeightInfo for () { /// Storage: DappStaking PeriodEnd (r:0 w:1) /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_voting() -> Weight { // Proof Size summary in bytes: // Measured: `550` // Estimated: `4254` - // Minimum execution time: 39_768_000 picoseconds. - Weight::from_parts(40_422_000, 4254) + // Minimum execution time: 41_147_000 picoseconds. + Weight::from_parts(42_304_000, 4254) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -793,13 +793,13 @@ impl WeightInfo for () { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_build_and_earn() -> Weight { // Proof Size summary in bytes: // Measured: `68` // Estimated: `4254` - // Minimum execution time: 20_976_000 picoseconds. - Weight::from_parts(21_507_000, 4254) + // Minimum execution time: 23_807_000 picoseconds. + Weight::from_parts(24_367_000, 4254) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -812,10 +812,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `152 + x * (32 ±0)` // Estimated: `3061 + x * (2071 ±0)` - // Minimum execution time: 7_374_000 picoseconds. - Weight::from_parts(10_826_637, 3061) - // Standard Error: 3_374 - .saturating_add(Weight::from_parts(2_291_643, 0).saturating_mul(x.into())) + // Minimum execution time: 7_821_000 picoseconds. + Weight::from_parts(12_000_144, 3061) + // Standard Error: 3_553 + .saturating_add(Weight::from_parts(2_396_421, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(Weight::from_parts(0, 2071).saturating_mul(x.into())) @@ -827,13 +827,13 @@ impl WeightInfo for () { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_idle_cleanup() -> Weight { // Proof Size summary in bytes: // Measured: `473` // Estimated: `4254` - // Minimum execution time: 14_500_000 picoseconds. - Weight::from_parts(14_969_000, 4254) + // Minimum execution time: 17_154_000 picoseconds. + Weight::from_parts(17_535_000, 4254) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 828dd717c..f46ccd201 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -612,7 +612,7 @@ impl> OnRuntimeUpgrade } // 1. Get & set inflation parameters - let (inflation_params, next_era) = P::get(); // TODO: re-check this later, whether it will be next or current era + let (inflation_params, next_era) = P::get(); InflationParams::::put(inflation_params.clone()); // 2. Calculation inflation config, set it & deposit event @@ -650,6 +650,8 @@ impl> OnRuntimeUpgrade config.recalculation_era = recalculation_era; }); + log::info!("Inflation pallet recalculation era set to {}.", recalculation_era); + T::DbWeight::get().reads_writes(1, 1).saturating_add(weight) } } diff --git a/pallets/inflation/src/weights.rs b/pallets/inflation/src/weights.rs index 1fa4cfb43..702c0f11b 100644 --- a/pallets/inflation/src/weights.rs +++ b/pallets/inflation/src/weights.rs @@ -20,9 +20,9 @@ //! Autogenerated weights for pallet_inflation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-01-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` +//! HOSTNAME: `gh-runner-01-ovh`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 // Executed Command: @@ -65,39 +65,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_036_000 picoseconds. - Weight::from_parts(9_186_000, 0) + // Minimum execution time: 9_487_000 picoseconds. + Weight::from_parts(9_652_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_set_inflation_config() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_073_000 picoseconds. - Weight::from_parts(9_411_000, 0) + // Minimum execution time: 9_168_000 picoseconds. + Weight::from_parts(9_436_000, 0) } /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn force_inflation_recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `58` + // Measured: `40` // Estimated: `1549` - // Minimum execution time: 14_839_000 picoseconds. - Weight::from_parts(15_198_000, 1549) + // Minimum execution time: 13_496_000 picoseconds. + Weight::from_parts(13_762_000, 1549) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `232` - // Estimated: `6196` - // Minimum execution time: 31_965_000 picoseconds. - Weight::from_parts(32_498_000, 6196) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `58` + // Estimated: `1549` + // Minimum execution time: 13_811_000 picoseconds. + Weight::from_parts(13_995_000, 1549) + .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -105,8 +102,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` - // Minimum execution time: 22_235_000 picoseconds. - Weight::from_parts(22_378_000, 6196) + // Minimum execution time: 21_351_000 picoseconds. + Weight::from_parts(21_749_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -120,39 +117,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_036_000 picoseconds. - Weight::from_parts(9_186_000, 0) + // Minimum execution time: 9_487_000 picoseconds. + Weight::from_parts(9_652_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn force_set_inflation_config() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_073_000 picoseconds. - Weight::from_parts(9_411_000, 0) + // Minimum execution time: 9_168_000 picoseconds. + Weight::from_parts(9_436_000, 0) } /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn force_inflation_recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `58` + // Measured: `40` // Estimated: `1549` - // Minimum execution time: 14_839_000 picoseconds. - Weight::from_parts(15_198_000, 1549) + // Minimum execution time: 13_496_000 picoseconds. + Weight::from_parts(13_762_000, 1549) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `232` - // Estimated: `6196` - // Minimum execution time: 31_965_000 picoseconds. - Weight::from_parts(32_498_000, 6196) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `58` + // Estimated: `1549` + // Minimum execution time: 13_811_000 picoseconds. + Weight::from_parts(13_995_000, 1549) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -160,8 +154,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` - // Minimum execution time: 22_235_000 picoseconds. - Weight::from_parts(22_378_000, 6196) + // Minimum execution time: 21_351_000 picoseconds. + Weight::from_parts(21_749_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/pallets/static-price-provider/src/lib.rs b/pallets/static-price-provider/src/lib.rs index 7e1c629e1..d71599c81 100644 --- a/pallets/static-price-provider/src/lib.rs +++ b/pallets/static-price-provider/src/lib.rs @@ -120,9 +120,11 @@ impl> OnRuntimeUpgrade for InitActivePrice { fn on_runtime_upgrade() -> Weight { let init_price = P::get().max(FixedU64::from_rational(1, FixedU64::DIV.into())); - log::info!("Setting initial active price to {:?}", init_price); + log::info!("Setting initial active price to {}", init_price); ActivePrice::::put(init_price); - T::DbWeight::get().writes(1) + STORAGE_VERSION.put::>(); + + T::DbWeight::get().writes(2) } } diff --git a/runtime/shibuya/src/weights/pallet_dapp_staking_v3.rs b/runtime/shibuya/src/weights/pallet_dapp_staking_v3.rs index 0bcfcee53..a922b3e6c 100644 --- a/runtime/shibuya/src/weights/pallet_dapp_staking_v3.rs +++ b/runtime/shibuya/src/weights/pallet_dapp_staking_v3.rs @@ -55,8 +55,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_474_000 picoseconds. - Weight::from_parts(8_711_000, 0) + // Minimum execution time: 9_265_000 picoseconds. + Weight::from_parts(9_422_000, 0) } /// Storage: DappStaking IntegratedDApps (r:1 w:1) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) @@ -68,8 +68,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3091` - // Minimum execution time: 16_360_000 picoseconds. - Weight::from_parts(16_697_000, 3091) + // Minimum execution time: 17_285_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -79,8 +79,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 12_927_000 picoseconds. - Weight::from_parts(13_229_000, 3091) + // Minimum execution time: 13_521_000 picoseconds. + Weight::from_parts(13_819_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -90,8 +90,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 13_610_000 picoseconds. - Weight::from_parts(13_851_000, 3091) + // Minimum execution time: 13_797_000 picoseconds. + Weight::from_parts(14_051_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -103,8 +103,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3091` - // Minimum execution time: 16_704_000 picoseconds. - Weight::from_parts(16_952_000, 3091) + // Minimum execution time: 17_242_000 picoseconds. + Weight::from_parts(17_628_000, 3091) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -120,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `12` // Estimated: `4764` - // Minimum execution time: 31_680_000 picoseconds. - Weight::from_parts(32_075_000, 4764) + // Minimum execution time: 32_138_000 picoseconds. + Weight::from_parts(32_677_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -137,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `156` // Estimated: `4764` - // Minimum execution time: 34_576_000 picoseconds. - Weight::from_parts(34_777_000, 4764) + // Minimum execution time: 33_789_000 picoseconds. + Weight::from_parts(34_052_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -155,10 +155,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `187` // Estimated: `4764` - // Minimum execution time: 33_562_000 picoseconds. - Weight::from_parts(34_600_552, 4764) - // Standard Error: 5_079 - .saturating_add(Weight::from_parts(193_345, 0).saturating_mul(x.into())) + // Minimum execution time: 35_048_000 picoseconds. + Weight::from_parts(36_286_241, 4764) + // Standard Error: 6_246 + .saturating_add(Weight::from_parts(176_805, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -174,8 +174,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `182` // Estimated: `4764` - // Minimum execution time: 36_436_000 picoseconds. - Weight::from_parts(37_262_000, 4764) + // Minimum execution time: 30_390_000 picoseconds. + Weight::from_parts(30_712_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -197,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `4764` - // Minimum execution time: 43_866_000 picoseconds. - Weight::from_parts(44_468_000, 4764) + // Minimum execution time: 44_866_000 picoseconds. + Weight::from_parts(45_342_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -220,8 +220,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `427` // Estimated: `4764` - // Minimum execution time: 47_368_000 picoseconds. - Weight::from_parts(48_049_000, 4764) + // Minimum execution time: 48_475_000 picoseconds. + Weight::from_parts(49_000_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -240,10 +240,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `560` // Estimated: `4764` - // Minimum execution time: 51_230_000 picoseconds. - Weight::from_parts(48_696_805, 4764) - // Standard Error: 6_139 - .saturating_add(Weight::from_parts(3_374_191, 0).saturating_mul(x.into())) + // Minimum execution time: 51_987_000 picoseconds. + Weight::from_parts(49_569_909, 4764) + // Standard Error: 5_547 + .saturating_add(Weight::from_parts(3_433_220, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -260,10 +260,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `501` // Estimated: `4764` - // Minimum execution time: 45_030_000 picoseconds. - Weight::from_parts(43_179_071, 4764) - // Standard Error: 5_547 - .saturating_add(Weight::from_parts(3_296_864, 0).saturating_mul(x.into())) + // Minimum execution time: 48_592_000 picoseconds. + Weight::from_parts(46_136_422, 4764) + // Standard Error: 4_476 + .saturating_add(Weight::from_parts(3_444_512, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -277,21 +277,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3775` - // Minimum execution time: 42_248_000 picoseconds. - Weight::from_parts(42_687_000, 3775) + // Minimum execution time: 38_973_000 picoseconds. + Weight::from_parts(39_533_000, 3775) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: DappStaking IntegratedDApps (r:1 w:0) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(121), added: 2101, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:1 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn claim_dapp_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `3021` - // Estimated: `5548` - // Minimum execution time: 50_968_000 picoseconds. - Weight::from_parts(51_778_000, 5548) + // Measured: `2585` + // Estimated: `5048` + // Minimum execution time: 54_909_000 picoseconds. + Weight::from_parts(55_839_000, 5048) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -311,8 +311,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `389` // Estimated: `4764` - // Minimum execution time: 42_329_000 picoseconds. - Weight::from_parts(42_737_000, 4764) + // Minimum execution time: 42_755_000 picoseconds. + Weight::from_parts(43_230_000, 4764) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -329,10 +329,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255 + x * (69 ±0)` // Estimated: `4764 + x * (2613 ±0)` - // Minimum execution time: 42_222_000 picoseconds. - Weight::from_parts(38_945_386, 4764) - // Standard Error: 14_325 - .saturating_add(Weight::from_parts(5_044_310, 0).saturating_mul(x.into())) + // Minimum execution time: 39_922_000 picoseconds. + Weight::from_parts(36_255_858, 4764) + // Standard Error: 14_366 + .saturating_add(Weight::from_parts(5_135_083, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -343,8 +343,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_971_000 picoseconds. - Weight::from_parts(10_190_000, 0) + // Minimum execution time: 11_519_000 picoseconds. + Weight::from_parts(11_865_000, 0) } /// Storage: DappStaking CurrentEraInfo (r:1 w:1) /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) @@ -354,8 +354,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16` // Estimated: `4254` - // Minimum execution time: 17_308_000 picoseconds. - Weight::from_parts(17_774_000, 4254) + // Minimum execution time: 17_823_000 picoseconds. + Weight::from_parts(18_413_000, 4254) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -370,13 +370,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking PeriodEnd (r:0 w:1) /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_voting() -> Weight { // Proof Size summary in bytes: // Measured: `550` // Estimated: `4254` - // Minimum execution time: 39_768_000 picoseconds. - Weight::from_parts(40_422_000, 4254) + // Minimum execution time: 41_147_000 picoseconds. + Weight::from_parts(42_304_000, 4254) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -385,13 +385,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_initialize_build_and_earn_to_build_and_earn() -> Weight { // Proof Size summary in bytes: // Measured: `68` // Estimated: `4254` - // Minimum execution time: 20_976_000 picoseconds. - Weight::from_parts(21_507_000, 4254) + // Minimum execution time: 23_807_000 picoseconds. + Weight::from_parts(24_367_000, 4254) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -404,10 +404,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `152 + x * (32 ±0)` // Estimated: `3061 + x * (2071 ±0)` - // Minimum execution time: 7_374_000 picoseconds. - Weight::from_parts(10_826_637, 3061) - // Standard Error: 3_374 - .saturating_add(Weight::from_parts(2_291_643, 0).saturating_mul(x.into())) + // Minimum execution time: 7_821_000 picoseconds. + Weight::from_parts(12_000_144, 3061) + // Standard Error: 3_553 + .saturating_add(Weight::from_parts(2_396_421, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(Weight::from_parts(0, 2071).saturating_mul(x.into())) @@ -419,13 +419,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking EraRewards (r:1 w:1) /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(789), added: 3264, mode: MaxEncodedLen) /// Storage: DappStaking DAppTiers (r:0 w:1) - /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(2083), added: 4558, mode: MaxEncodedLen) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(1583), added: 4058, mode: MaxEncodedLen) fn on_idle_cleanup() -> Weight { // Proof Size summary in bytes: // Measured: `473` // Estimated: `4254` - // Minimum execution time: 14_500_000 picoseconds. - Weight::from_parts(14_969_000, 4254) + // Minimum execution time: 17_154_000 picoseconds. + Weight::from_parts(17_535_000, 4254) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } diff --git a/runtime/shibuya/src/weights/pallet_inflation.rs b/runtime/shibuya/src/weights/pallet_inflation.rs index 8a048bf35..1fdb896f5 100644 --- a/runtime/shibuya/src/weights/pallet_inflation.rs +++ b/runtime/shibuya/src/weights/pallet_inflation.rs @@ -57,39 +57,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_036_000 picoseconds. - Weight::from_parts(9_186_000, 0) + // Minimum execution time: 9_487_000 picoseconds. + Weight::from_parts(9_652_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_set_inflation_config() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_073_000 picoseconds. - Weight::from_parts(9_411_000, 0) + // Minimum execution time: 9_168_000 picoseconds. + Weight::from_parts(9_436_000, 0) } /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn force_inflation_recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `58` + // Measured: `40` // Estimated: `1549` - // Minimum execution time: 14_839_000 picoseconds. - Weight::from_parts(15_198_000, 1549) + // Minimum execution time: 13_496_000 picoseconds. + Weight::from_parts(13_762_000, 1549) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Inflation InflationParams (r:1 w:0) /// Proof: Inflation InflationParams (max_values: Some(1), max_size: Some(64), added: 559, mode: MaxEncodedLen) fn recalculation() -> Weight { // Proof Size summary in bytes: - // Measured: `232` - // Estimated: `6196` - // Minimum execution time: 31_965_000 picoseconds. - Weight::from_parts(32_498_000, 6196) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `58` + // Estimated: `1549` + // Minimum execution time: 13_811_000 picoseconds. + Weight::from_parts(13_995_000, 1549) + .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -97,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6196` - // Minimum execution time: 22_235_000 picoseconds. - Weight::from_parts(22_378_000, 6196) + // Minimum execution time: 21_351_000 picoseconds. + Weight::from_parts(21_749_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } From a6a65f83db13df6e54555bbfce2247845e4fe111 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 15 Jan 2024 14:57:19 +0100 Subject: [PATCH 12/16] Minor changes --- pallets/inflation/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index f46ccd201..cfb8eb411 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -224,8 +224,6 @@ pub mod pallet { // ActiveInflationConfig - 1 DB read // DoRecalculation - 1 DB read ::DbWeight::get().reads(2) - - // TODO: on_finalize weight! } fn on_finalize(_now: BlockNumber) { @@ -242,6 +240,8 @@ pub mod pallet { Self::deposit_event(Event::::NewInflationConfiguration { config }); } + + // NOTE: weight of the `on_finalize` logic with recalculation has to be covered by the observer notify call. } fn integrity_test() { From 5f4af43a9d9d4698a5faf64c53a4c068789925ff Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 15 Jan 2024 14:57:41 +0100 Subject: [PATCH 13/16] Format --- pallets/inflation/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index cfb8eb411..ef5286136 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -650,7 +650,10 @@ impl> OnRuntimeUpgrade config.recalculation_era = recalculation_era; }); - log::info!("Inflation pallet recalculation era set to {}.", recalculation_era); + log::info!( + "Inflation pallet recalculation era set to {}.", + recalculation_era + ); T::DbWeight::get().reads_writes(1, 1).saturating_add(weight) } From a8873e616d9d49e6fab60cc11d659c8c37b7895d Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 15 Jan 2024 15:41:43 +0100 Subject: [PATCH 14/16] Fixes --- chain-extensions/pallet-assets/src/mock.rs | 2 ++ pallets/dapp-staking-migration/src/mock.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/chain-extensions/pallet-assets/src/mock.rs b/chain-extensions/pallet-assets/src/mock.rs index 1ba7a0b8c..61ae25c4d 100644 --- a/chain-extensions/pallet-assets/src/mock.rs +++ b/chain-extensions/pallet-assets/src/mock.rs @@ -158,6 +158,8 @@ impl pallet_assets::Config for Test { type CallbackHandle = (); type Extra = (); type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/pallets/dapp-staking-migration/src/mock.rs b/pallets/dapp-staking-migration/src/mock.rs index 5da78a43e..587064118 100644 --- a/pallets/dapp-staking-migration/src/mock.rs +++ b/pallets/dapp-staking-migration/src/mock.rs @@ -181,6 +181,7 @@ impl pallet_dapp_staking_v3::Config for Test { type NativePriceProvider = DummyPriceProvider; type StakingRewardHandler = DummyStakingRewardHandler; type CycleConfiguration = DummyCycleConfiguration; + type Observers = (); type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<10>; From b27118be2bdc27521a5afb334861eabd9480b18d Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 15 Jan 2024 16:01:17 +0100 Subject: [PATCH 15/16] Fix failing UTs --- chain-extensions/pallet-assets/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chain-extensions/pallet-assets/Cargo.toml b/chain-extensions/pallet-assets/Cargo.toml index 72c69bb32..0bd86ecf9 100644 --- a/chain-extensions/pallet-assets/Cargo.toml +++ b/chain-extensions/pallet-assets/Cargo.toml @@ -46,3 +46,5 @@ std = [ "assets-chain-extension-types/std", "pallet-balances/std", ] +try-runtime = ["frame-support/try-runtime"] +runtime-benchmarks = ["pallet-assets/runtime-benchmarks"] From 0f8580bd594c0d132dc048261f09db6718419a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Wed, 17 Jan 2024 07:34:26 +0100 Subject: [PATCH 16/16] Fix for incorrect loyalty flag setting (#1136) --- pallets/dapp-staking-v3/src/test/testing_utils.rs | 13 +++++++++---- pallets/dapp-staking-v3/src/test/tests_types.rs | 13 ++++++++----- pallets/dapp-staking-v3/src/types.rs | 6 ++++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 999122bdb..1d03a8a4d 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -703,9 +703,14 @@ pub(crate) fn assert_unstake( ); let is_loyal = pre_staker_info.is_loyal() - && !(unstake_subperiod == Subperiod::BuildAndEarn - && post_staker_info.staked_amount(Subperiod::Voting) - < pre_staker_info.staked_amount(Subperiod::Voting)); + && match unstake_subperiod { + Subperiod::Voting => !post_staker_info.staked_amount(Subperiod::Voting).is_zero(), + Subperiod::BuildAndEarn => { + post_staker_info.staked_amount(Subperiod::Voting) + == pre_staker_info.staked_amount(Subperiod::Voting) + } + }; + assert_eq!( post_staker_info.is_loyal(), is_loyal, @@ -782,7 +787,7 @@ pub(crate) fn assert_claim_staker_rewards(account: AccountId) { .earliest_staked_era() .expect("Entry must exist, otherwise 'claim' is invalid."); - // Get the apprropriate era rewards span for the 'first era' + // Get the appropriate era rewards span for the 'first era' let era_span_length: EraNumber = ::EraRewardSpanLength::get(); let era_span_index = first_claim_era - (first_claim_era % era_span_length); let era_rewards_span = pre_snapshot diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 9d9a5d2e7..91d18964c 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -382,7 +382,7 @@ fn account_ledger_staked_amount_for_type_works() { build_and_earn_1 ); - // Inocrrect period should simply return 0 + // Incorrect period should simply return 0 assert!(acc_ledger .staked_amount_for_type(Subperiod::Voting, period - 1) .is_zero()); @@ -816,7 +816,7 @@ fn account_ledger_add_stake_amount_too_large_amount_fails() { Err(AccountLedgerError::UnavailableStakeFunds) ); - // Additional check - have some active stake, and then try to overstake + // Additional check - have some active stake, and then try to stake more than available assert!(acc_ledger .add_stake_amount(lock_amount - 2, era_1, period_info_1) .is_ok()); @@ -2113,7 +2113,7 @@ fn singular_staking_info_unstake_during_voting_is_ok() { "Stake era should remain valid." ); - // Fully unstake, attempting to undersaturate, and ensure loyalty flag is still true. + // Fully unstake, attempting to underflow, and ensure loyalty flag has been removed. let era_2 = era_1 + 2; let remaining_stake = staking_info.total_staked_amount(); assert_eq!( @@ -2121,7 +2121,10 @@ fn singular_staking_info_unstake_during_voting_is_ok() { (remaining_stake, Balance::zero()) ); assert!(staking_info.total_staked_amount().is_zero()); - assert!(staking_info.is_loyal()); + assert!( + !staking_info.is_loyal(), + "Loyalty flag should have been removed since it was full unstake." + ); assert_eq!(staking_info.era(), era_2); } @@ -2507,7 +2510,7 @@ fn contract_stake_amount_unstake_is_ok() { ); assert!( contract_stake.staked_future.is_none(), - "future enry should remain 'None'" + "future entry should remain 'None'" ); // 4th scenario - do a full unstake with existing future entry, expect a cleanup diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 1e9f2ac99..5216a5b79 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -1045,8 +1045,10 @@ impl SingularStakingInfo { self.staked.era = self.staked.era.max(current_era); self.loyal_staker = self.loyal_staker - && (subperiod == Subperiod::Voting - || subperiod == Subperiod::BuildAndEarn && self.staked.voting == snapshot.voting); + && match subperiod { + Subperiod::Voting => !self.staked.voting.is_zero(), + Subperiod::BuildAndEarn => self.staked.voting == snapshot.voting, + }; // Amount that was unstaked (