From aff1621516b9df0fa9105f19397e45684a5a6c4d Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Wed, 29 Nov 2023 16:50:49 +0100 Subject: [PATCH 01/30] dApp staking v3 part 6 From fc4b2b7d1732318db29d38a263828858404c9106 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Wed, 29 Nov 2023 17:08:46 +0100 Subject: [PATCH 02/30] Minor refactor of benchmarks --- .../{benchmarking.rs => benchmarking/mod.rs} | 157 +-------------- .../dapp-staking-v3/src/benchmarking/utils.rs | 181 ++++++++++++++++++ pallets/dapp-staking-v3/src/test/mock.rs | 2 +- 3 files changed, 184 insertions(+), 156 deletions(-) rename pallets/dapp-staking-v3/src/{benchmarking.rs => benchmarking/mod.rs} (83%) create mode 100644 pallets/dapp-staking-v3/src/benchmarking/utils.rs diff --git a/pallets/dapp-staking-v3/src/benchmarking.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs similarity index 83% rename from pallets/dapp-staking-v3/src/benchmarking.rs rename to pallets/dapp-staking-v3/src/benchmarking/mod.rs index 2b04874516..5a439cfadf 100644 --- a/pallets/dapp-staking-v3/src/benchmarking.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -26,161 +26,8 @@ use frame_system::{Pallet as System, RawOrigin}; use ::assert_matches::assert_matches; -// TODO: make benchmark utils file and move all these helper methods there to keep this file clean(er) - -// TODO2: non-extrinsic calls still need to be benchmarked. - -/// Run to the specified block number. -/// Function assumes first block has been initialized. -fn run_to_block(n: BlockNumberFor) { - while System::::block_number() < n { - DappStaking::::on_finalize(System::::block_number()); - System::::set_block_number(System::::block_number() + One::one()); - // This is performed outside of dapps staking but we expect it before on_initialize - DappStaking::::on_initialize(System::::block_number()); - } -} - -/// Run for the specified number of blocks. -/// Function assumes first block has been initialized. -fn run_for_blocks(n: BlockNumberFor) { - run_to_block::(System::::block_number() + n); -} - -/// Advance blocks until the specified era has been reached. -/// -/// Function has no effect if era is already passed. -pub(crate) fn advance_to_era(era: EraNumber) { - assert!(era >= ActiveProtocolState::::get().era); - while ActiveProtocolState::::get().era < era { - run_for_blocks::(One::one()); - } -} - -/// Advance blocks until next era has been reached. -pub(crate) fn advance_to_next_era() { - advance_to_era::(ActiveProtocolState::::get().era + 1); -} - -/// Advance blocks until the specified period has been reached. -/// -/// Function has no effect if period is already passed. -pub(crate) fn advance_to_period(period: PeriodNumber) { - assert!(period >= ActiveProtocolState::::get().period_number()); - while ActiveProtocolState::::get().period_number() < period { - run_for_blocks::(One::one()); - } -} - -/// Advance blocks until next period has been reached. -pub(crate) fn advance_to_next_period() { - advance_to_period::(ActiveProtocolState::::get().period_number() + 1); -} - -/// Advance blocks until next period type has been reached. -pub(crate) fn advance_to_next_subperiod() { - let subperiod = ActiveProtocolState::::get().subperiod(); - while ActiveProtocolState::::get().subperiod() == subperiod { - run_for_blocks::(One::one()); - } -} - -// All our networks use 18 decimals for native currency so this should be fine. -const UNIT: Balance = 1_000_000_000_000_000_000; - -// Minimum amount that must be staked on a dApp to enter any tier -const MIN_TIER_THRESHOLD: Balance = 10 * UNIT; - -const NUMBER_OF_SLOTS: u32 = 100; - -const SEED: u32 = 9000; - -/// Assert that the last event equals the provided one. -fn assert_last_event(generic_event: ::RuntimeEvent) { - frame_system::Pallet::::assert_last_event(generic_event.into()); -} - -// Return all dApp staking events from the event buffer. -fn dapp_staking_events() -> Vec> { - System::::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| ::RuntimeEvent::from(e).try_into().ok()) - .collect::>() -} - -// TODO: make it more generic per runtime? -pub fn initial_config() { - let era_length = T::StandardEraLength::get(); - let voting_period_length_in_eras = T::StandardErasPerVotingSubperiod::get(); - - // Init protocol state - ActiveProtocolState::::put(ProtocolState { - era: 1, - next_era_start: era_length.saturating_mul(voting_period_length_in_eras.into()) + One::one(), - period_info: PeriodInfo { - number: 1, - subperiod: Subperiod::Voting, - subperiod_end_era: 2, - }, - maintenance: false, - }); - - // Init tier params - let tier_params = TierParameters:: { - reward_portion: BoundedVec::try_from(vec![ - Permill::from_percent(40), - Permill::from_percent(30), - Permill::from_percent(20), - Permill::from_percent(10), - ]) - .unwrap(), - slot_distribution: BoundedVec::try_from(vec![ - Permill::from_percent(10), - Permill::from_percent(20), - Permill::from_percent(30), - Permill::from_percent(40), - ]) - .unwrap(), - tier_thresholds: BoundedVec::try_from(vec![ - TierThreshold::DynamicTvlAmount { - amount: 100 * UNIT, - minimum_amount: 80 * UNIT, - }, - TierThreshold::DynamicTvlAmount { - amount: 50 * UNIT, - minimum_amount: 40 * UNIT, - }, - TierThreshold::DynamicTvlAmount { - amount: 20 * UNIT, - minimum_amount: 20 * UNIT, - }, - TierThreshold::FixedTvlAmount { - amount: MIN_TIER_THRESHOLD, - }, - ]) - .unwrap(), - }; - - // Init tier config, based on the initial params - let init_tier_config = TiersConfiguration:: { - number_of_slots: NUMBER_OF_SLOTS.try_into().unwrap(), - slots_per_tier: BoundedVec::try_from(vec![10, 20, 30, 40]).unwrap(), - reward_portion: tier_params.reward_portion.clone(), - tier_thresholds: tier_params.tier_thresholds.clone(), - }; - - assert!(tier_params.is_valid()); - assert!(init_tier_config.is_valid()); - - StaticTierParams::::put(tier_params); - TierConfig::::put(init_tier_config.clone()); - NextTierConfig::::put(init_tier_config); -} - -fn max_number_of_contracts() -> u32 { - T::MaxNumberOfContracts::get().min(NUMBER_OF_SLOTS).into() -} +mod utils; +use utils::*; #[benchmarks] mod benchmarks { diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs new file mode 100644 index 0000000000..76214cca41 --- /dev/null +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -0,0 +1,181 @@ +// 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 . + +use super::{Pallet as DappStaking, *}; + +use astar_primitives::Balance; + +use frame_system::Pallet as System; + +/// Run to the specified block number. +/// Function assumes first block has been initialized. +pub(super) fn run_to_block(n: BlockNumberFor) { + while System::::block_number() < n { + DappStaking::::on_finalize(System::::block_number()); + System::::set_block_number(System::::block_number() + One::one()); + // This is performed outside of dapps staking but we expect it before on_initialize + DappStaking::::on_initialize(System::::block_number()); + } +} + +/// Run for the specified number of blocks. +/// Function assumes first block has been initialized. +pub(super) fn run_for_blocks(n: BlockNumberFor) { + run_to_block::(System::::block_number() + n); +} + +/// Advance blocks until the specified era has been reached. +/// +/// Function has no effect if era is already passed. +pub(super) fn advance_to_era(era: EraNumber) { + assert!(era >= ActiveProtocolState::::get().era); + while ActiveProtocolState::::get().era < era { + run_for_blocks::(One::one()); + } +} + +/// Advance blocks until next era has been reached. +pub(super) fn advance_to_next_era() { + advance_to_era::(ActiveProtocolState::::get().era + 1); +} + +/// Advance blocks until the specified period has been reached. +/// +/// Function has no effect if period is already passed. +pub(super) fn advance_to_period(period: PeriodNumber) { + assert!(period >= ActiveProtocolState::::get().period_number()); + while ActiveProtocolState::::get().period_number() < period { + run_for_blocks::(One::one()); + } +} + +/// Advance blocks until next period has been reached. +pub(super) fn advance_to_next_period() { + advance_to_period::(ActiveProtocolState::::get().period_number() + 1); +} + +/// Advance blocks until next period type has been reached. +pub(super) fn advance_to_next_subperiod() { + let subperiod = ActiveProtocolState::::get().subperiod(); + while ActiveProtocolState::::get().subperiod() == subperiod { + run_for_blocks::(One::one()); + } +} + +/// All our networks use 18 decimals for native currency so this should be fine. +pub(super) const UNIT: Balance = 1_000_000_000_000_000_000; + +/// Minimum amount that must be staked on a dApp to enter any tier +pub(super) const MIN_TIER_THRESHOLD: Balance = 10 * UNIT; + +/// Number of slots in the tier system. +pub(super) const NUMBER_OF_SLOTS: u32 = 100; + +/// Random seed. +pub(super) const SEED: u32 = 9000; + +/// Assert that the last event equals the provided one. +pub(super) fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +// Return all dApp staking events from the event buffer. +pub(super) fn dapp_staking_events() -> Vec> { + System::::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| ::RuntimeEvent::from(e).try_into().ok()) + .collect::>() +} + +/// Initialize dApp staking pallet with initial config. +/// +/// **NOTE:** This assumes similar tier configuration for all runtimes. +/// If we decide to change this, we'll need to provide a more generic init function. +pub(super) fn initial_config() { + let era_length = T::StandardEraLength::get(); + let voting_period_length_in_eras = T::StandardErasPerVotingSubperiod::get(); + + // Init protocol state + ActiveProtocolState::::put(ProtocolState { + era: 1, + next_era_start: era_length.saturating_mul(voting_period_length_in_eras.into()) + One::one(), + period_info: PeriodInfo { + number: 1, + subperiod: Subperiod::Voting, + subperiod_end_era: 2, + }, + maintenance: false, + }); + + // Init tier params + let tier_params = TierParameters:: { + reward_portion: BoundedVec::try_from(vec![ + Permill::from_percent(40), + Permill::from_percent(30), + Permill::from_percent(20), + Permill::from_percent(10), + ]) + .unwrap(), + slot_distribution: BoundedVec::try_from(vec![ + Permill::from_percent(10), + Permill::from_percent(20), + Permill::from_percent(30), + Permill::from_percent(40), + ]) + .unwrap(), + tier_thresholds: BoundedVec::try_from(vec![ + TierThreshold::DynamicTvlAmount { + amount: 100 * UNIT, + minimum_amount: 80 * UNIT, + }, + TierThreshold::DynamicTvlAmount { + amount: 50 * UNIT, + minimum_amount: 40 * UNIT, + }, + TierThreshold::DynamicTvlAmount { + amount: 20 * UNIT, + minimum_amount: 20 * UNIT, + }, + TierThreshold::FixedTvlAmount { + amount: MIN_TIER_THRESHOLD, + }, + ]) + .unwrap(), + }; + + // Init tier config, based on the initial params + let init_tier_config = TiersConfiguration:: { + number_of_slots: NUMBER_OF_SLOTS.try_into().unwrap(), + slots_per_tier: BoundedVec::try_from(vec![10, 20, 30, 40]).unwrap(), + reward_portion: tier_params.reward_portion.clone(), + tier_thresholds: tier_params.tier_thresholds.clone(), + }; + + assert!(tier_params.is_valid()); + assert!(init_tier_config.is_valid()); + + StaticTierParams::::put(tier_params); + TierConfig::::put(init_tier_config.clone()); + NextTierConfig::::put(init_tier_config); +} + +/// Maximum number of contracts that 'makes sense' - considers both contract number limit & number of slots. +pub(super) fn max_number_of_contracts() -> u32 { + T::MaxNumberOfContracts::get().min(NUMBER_OF_SLOTS).into() +} diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 73535acd36..44b80021b3 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -268,7 +268,7 @@ impl ExtBuilder { pallet_dapp_staking::NextTierConfig::::put(init_tier_config); // TODO: include this into every test unless it explicitly doesn't need it. - // DappStaking::on_initialize(System::block_number()); + DappStaking::on_initialize(System::block_number()); } ); From d3b000c0f772b8eca13b1b6c840fc356eb104edc Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Wed, 29 Nov 2023 18:15:33 +0100 Subject: [PATCH 03/30] Weights integration --- pallets/dapp-staking-v3/src/dsv3_weight.rs | 100 --- pallets/dapp-staking-v3/src/lib.rs | 73 +- pallets/dapp-staking-v3/src/test/mock.rs | 2 +- pallets/dapp-staking-v3/src/test/tests.rs | 39 -- pallets/dapp-staking-v3/src/weights.rs | 735 +++++++++++++++++++++ runtime/local/src/lib.rs | 3 +- 6 files changed, 784 insertions(+), 168 deletions(-) delete mode 100644 pallets/dapp-staking-v3/src/dsv3_weight.rs create mode 100644 pallets/dapp-staking-v3/src/weights.rs diff --git a/pallets/dapp-staking-v3/src/dsv3_weight.rs b/pallets/dapp-staking-v3/src/dsv3_weight.rs deleted file mode 100644 index c1f88e9f1a..0000000000 --- a/pallets/dapp-staking-v3/src/dsv3_weight.rs +++ /dev/null @@ -1,100 +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 . - -//! Autogenerated weights for pallet_dapp_staking_v3 -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Dinos-MBP`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/astar-collator -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_dapp_staking-v3 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=dapp_staking_v3.rs -// --template=./scripts/templates/weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for pallet_dapp_staking_v3. -pub trait WeightInfo { - fn dapp_tier_assignment(x: u32, ) -> Weight; -} - -/// Weights for pallet_dapp_staking_v3 using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: DappStaking CounterForIntegratedDApps (r:1 w:0) - /// Proof: DappStaking CounterForIntegratedDApps (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: DappStaking ContractStake (r:101 w:0) - /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) - /// Storage: DappStaking TierConfig (r:1 w:0) - /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) - /// The range of component `x` is `[0, 100]`. - fn dapp_tier_assignment(x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `449 + x * (33 ±0)` - // Estimated: `3063 + x * (2073 ±0)` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(16_776_512, 3063) - // Standard Error: 3_400 - .saturating_add(Weight::from_parts(2_636_298, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 2073).saturating_mul(x.into())) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - /// Storage: DappStaking CounterForIntegratedDApps (r:1 w:0) - /// Proof: DappStaking CounterForIntegratedDApps (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: DappStaking ContractStake (r:101 w:0) - /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) - /// Storage: DappStaking TierConfig (r:1 w:0) - /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) - /// The range of component `x` is `[0, 100]`. - fn dapp_tier_assignment(x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `449 + x * (33 ±0)` - // Estimated: `3063 + x * (2073 ±0)` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(16_776_512, 3063) - // Standard Error: 3_400 - .saturating_add(Weight::from_parts(2_636_298, 0).saturating_mul(x.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 2073).saturating_mul(x.into())) - } -} diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index e282f0959f..071e35d99c 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -66,7 +66,8 @@ mod types; use types::*; pub use types::{PriceProvider, RewardPoolProvider, TierThreshold}; -mod dsv3_weight; +mod weights; +pub use weights::WeightInfo; // Lock identifier for the dApp staking pallet const STAKING_ID: LockIdentifier = *b"dapstake"; @@ -159,7 +160,7 @@ pub mod pallet { #[pallet::constant] type UnlockingPeriod: Get; - /// Maximum amount of stake entries contract is allowed to have at once. + /// Maximum amount of stake contract entries acount is allowed to have at once. #[pallet::constant] type MaxNumberOfStakedContracts: Get; @@ -171,6 +172,9 @@ pub mod pallet { #[pallet::constant] type NumberOfTiers: Get; + /// Weight info for various calls & operations in the pallet. + type WeightInfo: WeightInfo; + /// Helper trait for benchmarks. #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper: BenchmarkHelper; @@ -350,6 +354,7 @@ pub mod pallet { /// General information about dApp staking protocol state. #[pallet::storage] + #[pallet::whitelist_storage] pub type ActiveProtocolState = StorageValue<_, ProtocolState>, ValueQuery>; @@ -658,7 +663,7 @@ pub mod pallet { /// Used to enable or disable maintenance mode. /// Can only be called by manager origin. #[pallet::call_index(0)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::maintenance_mode())] pub fn maintenance_mode(origin: OriginFor, enabled: bool) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; ActiveProtocolState::::mutate(|state| state.maintenance = enabled); @@ -672,7 +677,7 @@ pub mod pallet { /// If successful, smart contract will be assigned a simple, unique numerical identifier. /// Owner is set to be initial beneficiary & manager of the dApp. #[pallet::call_index(1)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::register())] pub fn register( origin: OriginFor, owner: T::AccountId, @@ -723,7 +728,7 @@ pub mod pallet { /// If set to `None`, rewards will be deposited to the dApp owner. /// After this call, all existing & future rewards will be paid out to the beneficiary. #[pallet::call_index(2)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::set_dapp_reward_beneficiary())] pub fn set_dapp_reward_beneficiary( origin: OriginFor, smart_contract: T::SmartContract, @@ -762,7 +767,7 @@ pub mod pallet { /// 1. when the dApp owner account is compromised, manager can change the owner to a new account /// 2. if project wants to transfer ownership to a new account (DAO, multisig, etc.). #[pallet::call_index(3)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::set_dapp_owner())] pub fn set_dapp_owner( origin: OriginFor, smart_contract: T::SmartContract, @@ -802,7 +807,7 @@ pub mod pallet { /// /// Can be called by dApp staking manager origin. #[pallet::call_index(4)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::unregister())] pub fn unregister( origin: OriginFor, smart_contract: T::SmartContract, @@ -840,7 +845,7 @@ pub mod pallet { /// /// Locked amount can immediately be used for staking. #[pallet::call_index(5)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::lock())] pub fn lock(origin: OriginFor, #[pallet::compact] amount: Balance) -> DispatchResult { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -879,7 +884,7 @@ pub mod pallet { /// If the amount is greater than the available amount for unlocking, everything is unlocked. /// If the remaining locked amount would take the account below the minimum locked amount, everything is unlocked. #[pallet::call_index(6)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::unlock())] pub fn unlock(origin: OriginFor, #[pallet::compact] amount: Balance) -> DispatchResult { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -932,8 +937,8 @@ pub mod pallet { /// Claims all of fully unlocked chunks, removing the lock from them. #[pallet::call_index(7)] - #[pallet::weight(Weight::zero())] - pub fn claim_unlocked(origin: OriginFor) -> DispatchResult { + #[pallet::weight(T::WeightInfo::claim_unlocked(T::MaxNumberOfStakedContracts::get()))] + pub fn claim_unlocked(origin: OriginFor) -> DispatchResultWithPostInfo { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -944,8 +949,7 @@ pub mod pallet { ensure!(amount > Zero::zero(), Error::::NoUnlockedChunksToClaim); // In case it's full unlock, account is exiting dApp staking, ensure all storage is cleaned up. - // TODO: will be used after benchmarks - let _removed_entries = if ledger.is_empty() { + let removed_entries = if ledger.is_empty() { let _ = StakerInfo::::clear_prefix(&account, ledger.contract_stake_count, None); ledger.contract_stake_count } else { @@ -959,11 +963,11 @@ pub mod pallet { Self::deposit_event(Event::::ClaimedUnlocked { account, amount }); - Ok(()) + Ok(Some(T::WeightInfo::claim_unlocked(removed_entries)).into()) } #[pallet::call_index(8)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::relock_unlocking())] pub fn relock_unlocking(origin: OriginFor) -> DispatchResult { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -1000,7 +1004,7 @@ pub mod pallet { /// /// Staked amount is only eligible for rewards from the next era onwards. #[pallet::call_index(9)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::stake())] pub fn stake( origin: OriginFor, smart_contract: T::SmartContract, @@ -1127,7 +1131,7 @@ pub mod pallet { /// In case amount is unstaked during `Build&Earn` subperiod, first the `build_and_earn` is reduced, /// and any spillover is subtracted from the `voting` amount. #[pallet::call_index(10)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::unstake())] pub fn unstake( origin: OriginFor, smart_contract: T::SmartContract, @@ -1229,8 +1233,12 @@ pub mod pallet { /// Claims some staker rewards, if user has any. /// In the case of a successfull call, at least one era will be claimed, with the possibility of multiple claims happening. #[pallet::call_index(11)] - #[pallet::weight(Weight::zero())] - pub fn claim_staker_rewards(origin: OriginFor) -> DispatchResult { + #[pallet::weight({ + let max_span_length = T::EraRewardSpanLength::get(); + T::WeightInfo::claim_staker_rewards_ongoing_period(max_span_length) + .max(T::WeightInfo::claim_staker_rewards_past_period(max_span_length)) + })] + pub fn claim_staker_rewards(origin: OriginFor) -> DispatchResultWithPostInfo { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -1294,6 +1302,7 @@ pub mod pallet { rewards.push((era, staker_reward)); reward_sum.saturating_accrue(staker_reward); } + let rewards_len: u32 = rewards.len().unique_saturated_into(); // TODO: add extra layer of security here to prevent excessive minting. Probably via Tokenomics2.0 pallet. // Account exists since it has locked funds. @@ -1310,12 +1319,17 @@ pub mod pallet { }); }); - Ok(()) + Ok(Some(if period_end.is_some() { + T::WeightInfo::claim_staker_rewards_past_period(rewards_len) + } else { + T::WeightInfo::claim_staker_rewards_ongoing_period(rewards_len) + }) + .into()) } /// Used to claim bonus reward for a smart contract, if eligible. #[pallet::call_index(12)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::claim_bonus_reward())] pub fn claim_bonus_reward( origin: OriginFor, smart_contract: T::SmartContract, @@ -1379,7 +1393,7 @@ pub mod pallet { /// Used to claim dApp reward for the specified era. #[pallet::call_index(13)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::claim_dapp_reward())] pub fn claim_dapp_reward( origin: OriginFor, smart_contract: T::SmartContract, @@ -1435,7 +1449,7 @@ pub mod pallet { /// Used to unstake funds from a contract that was unregistered after an account staked on it. /// This is required if staker wants to re-stake these funds on another active contract during the ongoing period. #[pallet::call_index(14)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::unstake_from_unregistered())] pub fn unstake_from_unregistered( origin: OriginFor, smart_contract: T::SmartContract, @@ -1507,8 +1521,10 @@ pub mod pallet { /// 1. It's from a past period & the account wasn't a loyal staker, meaning there's no claimable bonus reward. /// 2. It's from a period older than the oldest claimable period, regardless whether the account was loyal or not. #[pallet::call_index(15)] - #[pallet::weight(Weight::zero())] - pub fn cleanup_expired_entries(origin: OriginFor) -> DispatchResult { + #[pallet::weight(T::WeightInfo::cleanup_expired_entries( + T::MaxNumberOfStakedContracts::get() + ))] + pub fn cleanup_expired_entries(origin: OriginFor) -> DispatchResultWithPostInfo { Self::ensure_pallet_enabled()?; let account = ensure_signed(origin)?; @@ -1551,7 +1567,10 @@ pub mod pallet { count: entries_to_delete.unique_saturated_into(), }); - Ok(()) + Ok(Some(T::WeightInfo::cleanup_expired_entries( + entries_to_delete.unique_saturated_into(), + )) + .into()) } /// Used to force a change of era or subperiod. @@ -1562,7 +1581,7 @@ pub mod pallet { /// /// Can only be called by manager origin. #[pallet::call_index(16)] - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::force())] pub fn force(origin: OriginFor, forcing_type: ForcingType) -> DispatchResult { Self::ensure_pallet_enabled()?; T::ManagerOrigin::ensure_origin(origin)?; diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 44b80021b3..18c5bd293d 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -169,6 +169,7 @@ impl pallet_dapp_staking::Config for Test { type MaxNumberOfStakedContracts = ConstU32<5>; type MinimumStakeAmount = ConstU128<3>; type NumberOfTiers = ConstU32<4>; + type WeightInfo = weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper; } @@ -267,7 +268,6 @@ impl ExtBuilder { pallet_dapp_staking::TierConfig::::put(init_tier_config.clone()); pallet_dapp_staking::NextTierConfig::::put(init_tier_config); - // TODO: include this into every test unless it explicitly doesn't need it. DappStaking::on_initialize(System::block_number()); } ); diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 0795bd0653..42ec37c09b 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -29,45 +29,6 @@ use frame_support::{ }; use sp_runtime::traits::Zero; -// TODO: remove this prior to the merge -#[test] -fn print_test() { - ExtBuilder::build().execute_with(|| { - use crate::dsv3_weight::WeightInfo; - println!( - ">>> dApp tier assignment reading & calculation {:?}", - crate::dsv3_weight::SubstrateWeight::::dapp_tier_assignment(100) - ); - - use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; - use scale_info::TypeInfo; - - #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] - struct RewardSize; - impl Get for RewardSize { - fn get() -> u32 { - 1_00_u32 - } - } - #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] - struct TierSize; - impl Get for TierSize { - fn get() -> u32 { - 4_u32 - } - } - println!( - ">>> Max encoded size for dapp tier rewards: {:?}", - crate::DAppTierRewards::::max_encoded_len() - ); - - println!( - ">>> Max encoded size of ContractStake: {:?}", - crate::ContractStakeAmount::max_encoded_len() - ); - }) -} - #[test] fn maintenace_mode_works() { ExtBuilder::build().execute_with(|| { diff --git a/pallets/dapp-staking-v3/src/weights.rs b/pallets/dapp-staking-v3/src/weights.rs new file mode 100644 index 0000000000..9ed97ee431 --- /dev/null +++ b/pallets/dapp-staking-v3/src/weights.rs @@ -0,0 +1,735 @@ + +// 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 . + +//! Autogenerated weights for pallet_dapp_staking_v3 +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Dinos-MacBook-Pro.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/astar-collator +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_dapp_staking_v3 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=weights.rs +// --template=./scripts/templates/weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for pallet_dapp_staking_v3. +pub trait WeightInfo { + fn maintenance_mode() -> Weight; + fn register() -> Weight; + fn set_dapp_reward_beneficiary() -> Weight; + fn set_dapp_owner() -> Weight; + fn unregister() -> Weight; + fn lock() -> Weight; + fn unlock() -> Weight; + fn full_unlock() -> Weight; + fn claim_unlocked(x: u32, ) -> Weight; + fn relock_unlocking() -> Weight; + fn stake() -> Weight; + fn unstake() -> Weight; + fn claim_staker_rewards_past_period(x: u32, ) -> Weight; + fn claim_staker_rewards_ongoing_period(x: u32, ) -> Weight; + fn claim_bonus_reward() -> Weight; + fn claim_dapp_reward() -> Weight; + fn unstake_from_unregistered() -> Weight; + fn cleanup_expired_entries(x: u32, ) -> Weight; + fn force() -> Weight; + fn dapp_tier_assignment(x: u32, ) -> Weight; +} + +/// Weights for pallet_dapp_staking_v3 using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn maintenance_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking CounterForIntegratedDApps (r:1 w:1) + /// Proof: DappStaking CounterForIntegratedDApps (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: DappStaking NextDAppId (r:1 w:1) + /// Proof: DappStaking NextDAppId (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3093` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3093) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + fn set_dapp_reward_beneficiary() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3093) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + fn set_dapp_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3093) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:0 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + fn unregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3093) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn lock() -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `4764` + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `163` + // Estimated: `4764` + // Minimum execution time: 36_000_000 picoseconds. + Weight::from_parts(41_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn full_unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `163` + // Estimated: `4764` + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(44_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// The range of component `x` is `[0, 3]`. + fn claim_unlocked(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `160 + x * (17 ±0)` + // Estimated: `4764` + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(35_583_071, 4764) + // Standard Error: 69_897 + .saturating_add(Weight::from_parts(1_471_498, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn relock_unlocking() -> Weight { + // Proof Size summary in bytes: + // Measured: `174` + // Estimated: `4764` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:1 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn stake() -> Weight { + // Proof Size summary in bytes: + // Measured: `258` + // Estimated: `4764` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(45_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:1 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn unstake() -> Weight { + // Proof Size summary in bytes: + // Measured: `437` + // Estimated: `4764` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(54_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:0) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking PeriodEnd (r:1 w:0) + /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 8]`. + fn claim_staker_rewards_past_period(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `485 + x * (8 ±0)` + // Estimated: `4764` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(55_476_077, 4764) + // Standard Error: 72_725 + .saturating_add(Weight::from_parts(4_049_981, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:0) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 8]`. + fn claim_staker_rewards_ongoing_period(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `438 + x * (8 ±0)` + // Estimated: `4764` + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(47_715_646, 4764) + // Standard Error: 41_836 + .saturating_add(Weight::from_parts(4_504_988, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking PeriodEnd (r:1 w:0) + /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + fn claim_bonus_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `158` + // Estimated: `3603` + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(42_000_000, 3603) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking DAppTiers (r:1 w:1) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(483), added: 2958, mode: MaxEncodedLen) + fn claim_dapp_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `1086` + // Estimated: `3948` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(50_000_000, 3948) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn unstake_from_unregistered() -> Weight { + // Proof Size summary in bytes: + // Measured: `397` + // Estimated: `4764` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(48_000_000, 4764) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: DappStaking StakerInfo (r:4 w:3) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 3]`. + fn cleanup_expired_entries(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `250 + x * (75 ±0)` + // Estimated: `4764 + x * (2613 ±0)` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(40_563_259, 4764) + // Standard Error: 133_516 + .saturating_add(Weight::from_parts(6_899_171, 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)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 2613).saturating_mul(x.into())) + } + fn force() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) + } + /// Storage: DappStaking ContractStake (r:101 w:0) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:1 w:0) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// The range of component `x` is `[0, 100]`. + fn dapp_tier_assignment(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `158 + x * (33 ±0)` + // Estimated: `3063 + x * (2073 ±0)` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(15_026_604, 3063) + // Standard Error: 6_050 + .saturating_add(Weight::from_parts(2_666_223, 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, 2073).saturating_mul(x.into())) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn maintenance_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking CounterForIntegratedDApps (r:1 w:1) + /// Proof: DappStaking CounterForIntegratedDApps (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: DappStaking NextDAppId (r:1 w:1) + /// Proof: DappStaking NextDAppId (max_values: Some(1), max_size: Some(2), added: 497, mode: MaxEncodedLen) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3093` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3093) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + fn set_dapp_reward_beneficiary() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3093) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + fn set_dapp_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3093) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:1) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:0 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + fn unregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3093` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3093) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn lock() -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `4764` + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `163` + // Estimated: `4764` + // Minimum execution time: 36_000_000 picoseconds. + Weight::from_parts(41_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn full_unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `163` + // Estimated: `4764` + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(44_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// The range of component `x` is `[0, 3]`. + fn claim_unlocked(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `160 + x * (17 ±0)` + // Estimated: `4764` + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(35_583_071, 4764) + // Standard Error: 69_897 + .saturating_add(Weight::from_parts(1_471_498, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + fn relock_unlocking() -> Weight { + // Proof Size summary in bytes: + // Measured: `174` + // Estimated: `4764` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:1 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn stake() -> Weight { + // Proof Size summary in bytes: + // Measured: `258` + // Estimated: `4764` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(45_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking ContractStake (r:1 w:1) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn unstake() -> Weight { + // Proof Size summary in bytes: + // Measured: `437` + // Estimated: `4764` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(54_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:0) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking PeriodEnd (r:1 w:0) + /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 8]`. + fn claim_staker_rewards_past_period(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `485 + x * (8 ±0)` + // Estimated: `4764` + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(55_476_077, 4764) + // Standard Error: 72_725 + .saturating_add(Weight::from_parts(4_049_981, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:0) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 8]`. + fn claim_staker_rewards_ongoing_period(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `438 + x * (8 ±0)` + // Estimated: `4764` + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(47_715_646, 4764) + // Standard Error: 41_836 + .saturating_add(Weight::from_parts(4_504_988, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking PeriodEnd (r:1 w:0) + /// Proof: DappStaking PeriodEnd (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + fn claim_bonus_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `158` + // Estimated: `3603` + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(42_000_000, 3603) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking DAppTiers (r:1 w:1) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(483), added: 2958, mode: MaxEncodedLen) + fn claim_dapp_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `1086` + // Estimated: `3948` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(50_000_000, 3948) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: DappStaking IntegratedDApps (r:1 w:0) + /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) + /// Storage: DappStaking StakerInfo (r:1 w:1) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn unstake_from_unregistered() -> Weight { + // Proof Size summary in bytes: + // Measured: `397` + // Estimated: `4764` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(48_000_000, 4764) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: DappStaking StakerInfo (r:4 w:3) + /// Proof: DappStaking StakerInfo (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: DappStaking Ledger (r:1 w:1) + /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// The range of component `x` is `[1, 3]`. + fn cleanup_expired_entries(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `250 + x * (75 ±0)` + // Estimated: `4764 + x * (2613 ±0)` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(40_563_259, 4764) + // Standard Error: 133_516 + .saturating_add(Weight::from_parts(6_899_171, 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)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 2613).saturating_mul(x.into())) + } + fn force() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) + } + /// Storage: DappStaking ContractStake (r:101 w:0) + /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:1 w:0) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// The range of component `x` is `[0, 100]`. + fn dapp_tier_assignment(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `158 + x * (33 ±0)` + // Estimated: `3063 + x * (2073 ±0)` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(15_026_604, 3063) + // Standard Error: 6_050 + .saturating_add(Weight::from_parts(2_666_223, 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, 2073).saturating_mul(x.into())) + } +} diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index ab8217a9ff..b27f8c41d8 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -480,7 +480,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type RewardPoolProvider = DummyRewardPoolProvider; type StandardEraLength = ConstU32<30>; // should be 1 minute per standard era type StandardErasPerVotingSubperiod = ConstU32<2>; - type StandardErasPerBuildAndEarnSubperiod = ConstU32<10>; + type StandardErasPerBuildAndEarnSubperiod = ConstU32<22>; type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<100>; @@ -490,6 +490,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type MaxNumberOfStakedContracts = ConstU32<3>; type MinimumStakeAmount = ConstU128; type NumberOfTiers = ConstU32<4>; + type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper>; } From 958b013b25d51f73dffdec80d236b84d82b79118 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Thu, 30 Nov 2023 17:25:22 +0100 Subject: [PATCH 04/30] Fix --- pallets/dapp-staking-v3/src/lib.rs | 2 +- runtime/local/src/lib.rs | 2 +- runtime/local/src/lib.rs.orig | 1893 ++++++++++++++++++++++++++++ 3 files changed, 1895 insertions(+), 2 deletions(-) create mode 100644 runtime/local/src/lib.rs.orig diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 071e35d99c..dd26da7a2b 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -66,7 +66,7 @@ mod types; use types::*; pub use types::{PriceProvider, RewardPoolProvider, TierThreshold}; -mod weights; +pub mod weights; pub use weights::WeightInfo; // Lock identifier for the dApp staking pallet diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 1abef46fed..e34d419af0 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -497,7 +497,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type MaxNumberOfStakedContracts = ConstU32<3>; type MinimumStakeAmount = ConstU128; type NumberOfTiers = ConstU32<4>; - type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; + type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper>; } diff --git a/runtime/local/src/lib.rs.orig b/runtime/local/src/lib.rs.orig new file mode 100644 index 0000000000..779261f6ef --- /dev/null +++ b/runtime/local/src/lib.rs.orig @@ -0,0 +1,1893 @@ +// 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_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use frame_support::{ + construct_runtime, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Currency, EitherOfDiverse, + EqualPrivilegeOnly, FindAuthor, Get, InstanceFilter, Nothing, OnFinalize, WithdrawReasons, + }, + weights::{ + constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + ConstantMultiplier, IdentityFee, Weight, + }, + ConsensusEngineId, PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, EnsureSigned, +}; +use pallet_ethereum::PostLogContent; +use pallet_evm::{FeeCalculator, GasWeightMapping, Runner}; +use pallet_evm_precompile_assets_erc20::AddressToAssetId; +use pallet_grandpa::{fg_primitives, AuthorityList as GrandpaAuthorityList}; +use parity_scale_codec::{Compact, Decode, Encode, MaxEncodedLen}; +use sp_api::impl_runtime_apis; +use sp_arithmetic::fixed_point::FixedU64; +use sp_core::{crypto::KeyTypeId, ConstBool, OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{ + AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, + DispatchInfoOf, Dispatchable, NumberFor, PostDispatchInfoOf, UniqueSaturatedInto, Verify, + }, + transaction_validity::{ + TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, RuntimeDebug, +}; +use sp_std::prelude::*; + +pub use astar_primitives::{ + evm::EvmRevertCodeHandler, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, + Index, Signature, +}; + +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +pub use frame_system::Call as SystemCall; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_grandpa::AuthorityId as GrandpaId; +pub use pallet_inflation::InflationParameters; +pub use pallet_timestamp::Call as TimestampCall; +use pallet_transaction_payment::CurrencyAdapter; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{Perbill, Permill}; + +#[cfg(feature = "std")] +/// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics. +pub fn wasm_binary_unwrap() -> &'static [u8] { + WASM_BINARY.expect( + "Development wasm binary is not available. This means the client is \ + built with `BUILD_DUMMY_WASM_BINARY` flag and it is only usable for \ + production chains. Please rebuild with the flag disabled.", + ) +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("local"), + impl_name: create_runtime_str!("local"), + authoring_version: 1, + spec_version: 1, + impl_version: 1, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + pub grandpa: Grandpa, + } +} + +mod precompiles; +pub use precompiles::{LocalNetworkPrecompiles, ASSET_PRECOMPILE_ADDRESS_PREFIX}; +pub type Precompiles = LocalNetworkPrecompiles; + +mod chain_extensions; +pub use chain_extensions::*; + +mod weights; + +/// Constant values used within the runtime. +pub const MICROAST: Balance = 1_000_000_000_000; +pub const MILLIAST: Balance = 1_000 * MICROAST; +pub const AST: Balance = 1_000 * MILLIAST; + +pub const STORAGE_BYTE_FEE: Balance = 100 * MICROAST; + +/// Charge fee for stored bytes and items. +pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * AST + (bytes as Balance) * STORAGE_BYTE_FEE +} + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 2000; +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +impl AddressToAssetId for Runtime { + fn address_to_asset_id(address: H160) -> Option { + let mut data = [0u8; 16]; + let address_bytes: [u8; 20] = address.into(); + if ASSET_PRECOMPILE_ADDRESS_PREFIX.eq(&address_bytes[0..4]) { + data.copy_from_slice(&address_bytes[4..20]); + Some(u128::from_be_bytes(data)) + } else { + None + } + } + + fn asset_id_to_address(asset_id: AssetId) -> H160 { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(ASSET_PRECOMPILE_ADDRESS_PREFIX); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + H160::from(data) + } +} + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used +/// by Operational extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + pub const BlockHashCount: BlockNumber = 2400; + /// We allow for 1 seconds of compute with a 2 second average block time. + pub RuntimeBlockWeights: BlockWeights = BlockWeights + ::with_sensible_defaults(Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX), NORMAL_DISPATCH_RATIO); + pub RuntimeBlockLength: BlockLength = BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub const SS58Prefix: u8 = 5; +} + +// Configure FRAME pallets to include in runtime. + +impl frame_system::Config for Runtime { + /// The basic call filter to use in dispatchable. + type BaseCallFilter = frame_support::traits::Everything; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = generic::Header; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// Version of the runtime. + type Version = Version; + /// Converts a module to the index of the module in `construct_runtime!`. + /// + /// This type is being generated by `construct_runtime!`. + type PalletInfo = PalletInfo; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = frame_system::weights::SubstrateWeight; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const MaxAuthorities: u32 = 50; +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<50>; +} + +impl pallet_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); + + type WeightInfo = (); + type MaxAuthorities = MaxAuthorities; + type MaxSetIdSessionEntries = ConstU64<0>; +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (Aura, BlockReward); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = pallet_timestamp::weights::SubstrateWeight; +} + +impl pallet_insecure_randomness_collective_flip::Config for Runtime {} + +parameter_types! { + pub const ExistentialDeposit: u128 = 500; + pub const MaxLocks: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const AssetDeposit: Balance = 1 * AST; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = deposit(1, 68); + pub const MetadataDepositPerByte: Balance = deposit(0, 1); + pub const AssetAccountDeposit: Balance = deposit(1, 18); +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type AssetAccountDeposit = AssetAccountDeposit; + type ApprovalDeposit = ExistentialDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = weights::pallet_assets::SubstrateWeight; + type RemoveItemsLimit = ConstU32<1000>; + type AssetIdParameter = Compact; + type CallbackHandle = EvmRevertCodeHandler; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = astar_primitives::benchmarks::AssetsBenchmarkHelper; +} + +parameter_types! { + pub const TransactionByteFee: Balance = 1; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type WeightToFee = IdentityFee; + type OperationalFeeMultiplier = OperationalFeeMultiplier; + type FeeMultiplierUpdate = (); + type LengthToFee = ConstantMultiplier; +} + +parameter_types! { + pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const DappsStakingPalletId: PalletId = PalletId(*b"py/dpsst"); +} + +type NegativeImbalance = >::NegativeImbalance; + +pub struct DappsStakingTvlProvider(); +impl Get for DappsStakingTvlProvider { + fn get() -> Balance { + DappsStaking::tvl() + } +} + +pub struct BeneficiaryPayout(); +impl pallet_block_reward::BeneficiaryPayout for BeneficiaryPayout { + fn treasury(reward: NegativeImbalance) { + Balances::resolve_creating(&TreasuryPalletId::get().into_account_truncating(), reward); + } + + fn collators(_reward: NegativeImbalance) { + // no collators for local dev node + } + + fn dapps_staking(stakers: NegativeImbalance, dapps: NegativeImbalance) { + DappsStaking::rewards(stakers, dapps) + } +} + +parameter_types! { + pub const RewardAmount: Balance = 2_664 * MILLIAST; +} + +impl pallet_block_reward::Config for Runtime { + type Currency = Balances; + type DappsStakingTvlProvider = DappsStakingTvlProvider; + type BeneficiaryPayout = BeneficiaryPayout; + type RewardAmount = RewardAmount; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_block_reward::weights::SubstrateWeight; +} + +parameter_types! { + pub const BlockPerEra: BlockNumber = 60; + pub const RegisterDeposit: Balance = 100 * AST; + pub const MaxNumberOfStakersPerContract: u32 = 512; + pub const MinimumStakingAmount: Balance = 10 * AST; + pub const MinimumRemainingAmount: Balance = AST; + pub const MaxUnlockingChunks: u32 = 2; + pub const UnbondingPeriod: u32 = 2; + pub const MaxEraStakeValues: u32 = 5; +} + +impl pallet_dapps_staking::Config for Runtime { + type Currency = Balances; + type BlockPerEra = BlockPerEra; + type SmartContract = SmartContract; + type RegisterDeposit = RegisterDeposit; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_dapps_staking::weights::SubstrateWeight; + type MaxNumberOfStakersPerContract = MaxNumberOfStakersPerContract; + type MinimumStakingAmount = MinimumStakingAmount; + type PalletId = DappsStakingPalletId; + type MaxUnlockingChunks = MaxUnlockingChunks; + type UnbondingPeriod = UnbondingPeriod; + type MinimumRemainingAmount = MinimumRemainingAmount; + type MaxEraStakeValues = MaxEraStakeValues; + type UnregisteredDappRewardRetention = ConstU32<3>; +} + +/// Multi-VM pointer to smart contract instance. +#[derive( + PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, +)] +pub enum SmartContract { + /// EVM smart contract instance. + Evm(sp_core::H160), + /// Wasm smart contract instance. + Wasm(AccountId), +} + +impl Default for SmartContract { + fn default() -> Self { + SmartContract::Evm(H160::repeat_byte(0x00)) + } +} + +impl> From<[u8; 32]> for SmartContract { + fn from(input: [u8; 32]) -> Self { + SmartContract::Wasm(input.into()) + } +} + +pub struct DummyPriceProvider; +impl pallet_dapp_staking_v3::PriceProvider for DummyPriceProvider { + fn average_price() -> FixedU64 { + FixedU64::from_rational(1, 10) + } +} + +pub struct DummyRewardPoolProvider; +impl pallet_dapp_staking_v3::RewardPoolProvider for DummyRewardPoolProvider { + fn normal_reward_pools() -> (Balance, Balance) { + ( + Balance::from(1_000_000_000_000 * AST), + Balance::from(1_000_000_000 * AST), + ) + } + fn bonus_reward_pool() -> Balance { + Balance::from(3_000_000 * AST) + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct BenchmarkHelper(sp_std::marker::PhantomData); +#[cfg(feature = "runtime-benchmarks")] +impl pallet_dapp_staking_v3::BenchmarkHelper> + for BenchmarkHelper> +{ + fn get_smart_contract(id: u32) -> SmartContract { + SmartContract::Wasm(AccountId::from([id as u8; 32])) + } +} + +parameter_types! { + pub const StandardEraLength: BlockNumber = 30; // should be 1 minute per standard era + pub const StandardErasPerVotingSubperiod: u32 = 2; + pub const StandardErasPerBuildAndEarnSubperiod: u32 = 10; +} + +impl pallet_dapp_staking_v3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type SmartContract = SmartContract; + type ManagerOrigin = frame_system::EnsureRoot; + type NativePriceProvider = DummyPriceProvider; + type RewardPoolProvider = DummyRewardPoolProvider; +<<<<<<< HEAD + type StandardEraLength = ConstU32<30>; // should be 1 minute per standard era + type StandardErasPerVotingSubperiod = ConstU32<2>; + type StandardErasPerBuildAndEarnSubperiod = ConstU32<22>; +======= + type StandardEraLength = StandardEraLength; + type StandardErasPerVotingSubperiod = StandardErasPerVotingSubperiod; + type StandardErasPerBuildAndEarnSubperiod = StandardErasPerBuildAndEarnSubperiod; +>>>>>>> origin/feat/dapp-staking-v3 + type EraRewardSpanLength = ConstU32<8>; + type RewardRetentionInPeriods = ConstU32<2>; + type MaxNumberOfContracts = ConstU32<100>; + type MaxUnlockingChunks = ConstU32<5>; + type MinimumLockedAmount = ConstU128; + type UnlockingPeriod = ConstU32<2>; + type MaxNumberOfStakedContracts = ConstU32<3>; + type MinimumStakeAmount = ConstU128; + type NumberOfTiers = ConstU32<4>; + type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper>; +} + +pub struct InflationPayoutPerBlock; +impl pallet_inflation::PayoutPerBlock for InflationPayoutPerBlock { + fn treasury(reward: NegativeImbalance) { + Balances::resolve_creating(&TreasuryPalletId::get().into_account_truncating(), reward); + } + + fn collators(_reward: NegativeImbalance) { + // no collators for local dev node + } +} + +pub struct InflationCycleConfig; +impl pallet_inflation::CycleConfiguration for InflationCycleConfig { + fn periods_per_cycle() -> u32 { + 4 + } + + fn eras_per_voting_subperiod() -> u32 { + StandardErasPerVotingSubperiod::get() + } + + fn eras_per_build_and_earn_subperiod() -> u32 { + StandardErasPerBuildAndEarnSubperiod::get() + } + + fn blocks_per_era() -> u32 { + StandardEraLength::get() + } +} + +impl pallet_inflation::Config for Runtime { + type Currency = Balances; + type PayoutPerBlock = InflationPayoutPerBlock; + type CycleConfiguration = InflationCycleConfig; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_inflation::weights::SubstrateWeight; +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = pallet_utility::weights::SubstrateWeight; +} + +///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +parameter_types! { + /// Equal to normal class dispatch weight limit. + pub XvmTxWeightLimit: Weight = NORMAL_DISPATCH_RATIO * Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX); + pub ReservedXcmpWeight: Weight = Weight::zero(); +} + +impl pallet_ethereum_checked::Config for Runtime { + type ReservedXcmpWeight = ReservedXcmpWeight; + type XvmTxWeightLimit = XvmTxWeightLimit; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type AccountMapping = HashedAccountMapping; + type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; + type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; +} + +impl pallet_xvm::Config for Runtime { + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type AccountMapping = HashedAccountMapping; + type EthereumTransact = EthereumChecked; + type WeightInfo = pallet_xvm::weights::SubstrateWeight; +} + +parameter_types! { + // Tells `pallet_base_fee` whether to calculate a new BaseFee `on_finalize` or not. + pub DefaultBaseFeePerGas: U256 = (MILLIAST / 1_000_000).into(); + // At the moment, we don't use dynamic fee calculation for local chain by default + pub DefaultElasticity: Permill = Permill::zero(); +} + +pub struct BaseFeeThreshold; +impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold { + fn lower() -> Permill { + Permill::zero() + } + fn ideal() -> Permill { + Permill::from_parts(500_000) + } + fn upper() -> Permill { + Permill::from_parts(1_000_000) + } +} + +impl pallet_base_fee::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Threshold = BaseFeeThreshold; + type DefaultBaseFeePerGas = DefaultBaseFeePerGas; + type DefaultElasticity = DefaultElasticity; +} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 500ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND.saturating_div(GAS_PER_SECOND); + +pub struct FindAuthorTruncated(sp_std::marker::PhantomData); +impl> FindAuthor for FindAuthorTruncated { + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + if let Some(author_index) = F::find_author(digests) { + let authority_id = Aura::authorities()[author_index as usize].clone(); + return Some(H160::from_slice(&authority_id.encode()[4..24])); + } + + None + } +} + +parameter_types! { + /// Ethereum-compatible chain_id: + /// * Dusty: 80 + /// * Shibuya: 81 + /// * Shiden: 336 + /// * Local: 4369 + pub ChainId: u64 = 0x1111; + /// EVM gas limit + pub BlockGasLimit: U256 = U256::from( + NORMAL_DISPATCH_RATIO * WEIGHT_REF_TIME_PER_SECOND / WEIGHT_PER_GAS + ); + pub PrecompilesValue: Precompiles = LocalNetworkPrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per PoV size. Value is calculated as: + /// + /// max_gas_limit = max_tx_ref_time / WEIGHT_PER_GAS = max_pov_size * gas_limit_pov_size_ratio + /// gas_limit_pov_size_ratio = ceil((max_tx_ref_time / WEIGHT_PER_GAS) / max_pov_size) + /// + /// Local runtime has no strict bounds as parachain, but we keep the value set to 4 for consistency. + pub const GasLimitPovSizeRatio: u64 = 4; +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = BaseFee; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; + type AddressMapping = pallet_evm::HashedAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = Precompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = ChainId; + type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; + type BlockGasLimit = BlockGasLimit; + type Timestamp = Timestamp; + type OnCreate = (); + type FindAuthor = FindAuthorTruncated; + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + // Maximum length (in bytes) of revert message to include in Executed event + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub const EcdsaUnsignedPriority: TransactionPriority = TransactionPriority::MAX / 2; + pub const CallFee: Balance = AST / 10; + pub const CallMagicNumber: u16 = 0xff51; +} + +impl pallet_custom_signatures::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Signature = pallet_custom_signatures::ethereum::EthereumSignature; + type Signer = ::Signer; + type CallMagicNumber = CallMagicNumber; + type Currency = Balances; + type CallFee = CallFee; + type OnChargeTransaction = (); + type UnsignedPriority = EcdsaUnsignedPriority; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = deposit(1, 0); + pub const PreimageByteDeposit: Balance = deposit(0, 1); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type BaseDeposit = PreimageBaseDeposit; + type ByteDeposit = PreimageByteDeposit; +} + +parameter_types! { + pub CouncilMotionDuration: BlockNumber = 3 * MINUTES; + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +type CouncilCollective = pallet_collective::Instance1; +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = ConstU32<100>; + type MaxMembers = ConstU32<3>; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +parameter_types! { + pub const TechnicalCommitteeMotionDuration: BlockNumber = 3 * MINUTES; +} + +type TechnicalCommitteeCollective = pallet_collective::Instance2; +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + type MotionDuration = TechnicalCommitteeMotionDuration; + type MaxProposals = ConstU32<100>; + type MaxMembers = ConstU32<3>; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 100 * AST; + pub const ProposalBondMaximum: Balance = 500 * AST; + pub const SpendPeriod: BlockNumber = 1 * MINUTES; + pub const Burn: Permill = Permill::from_percent(1); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = ProposalBondMaximum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = pallet_treasury::weights::SubstrateWeight; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; +} + +parameter_types! { + pub LaunchPeriod: BlockNumber = 1 * MINUTES; + pub VotingPeriod: BlockNumber = 3 * MINUTES; + pub FastTrackVotingPeriod: BlockNumber = 1 * MINUTES; + pub const MinimumDeposit: Balance = 7000 * AST; + pub EnactmentPeriod: BlockNumber = 5 * MINUTES; + pub VoteLockingPeriod: BlockNumber = 10 * MINUTES; + pub CooloffPeriod: BlockNumber = 10 * MINUTES; + pub const InstantAllowed: bool = true; +} + +impl pallet_democracy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type EnactmentPeriod = EnactmentPeriod; + type LaunchPeriod = LaunchPeriod; + type VotingPeriod = VotingPeriod; + type VoteLockingPeriod = VoteLockingPeriod; + type MinimumDeposit = MinimumDeposit; + /// A straight majority of the council can decide what their next motion is. + type ExternalOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + /// A 60% super-majority can have the next scheduled referendum be a straight majority-carries vote. + type ExternalMajorityOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + /// A unanimous council can have the next scheduled referendum be a straight default-carries + /// (NTB) vote. + type ExternalDefaultOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + type SubmitOrigin = EnsureSigned; + /// Two thirds of the technical committee can have an `ExternalMajority/ExternalDefault` vote + /// be tabled immediately and with a shorter voting/enactment period. + type FastTrackOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + type InstantOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + type InstantAllowed = InstantAllowed; + type FastTrackVotingPeriod = FastTrackVotingPeriod; + // To cancel a proposal which has been passed, 2/3 of the council must agree to it. + type CancellationOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + // To cancel a proposal before it has been passed, the technical committee must be unanimous or + // Root must agree. + type CancelProposalOrigin = EitherOfDiverse< + pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + >; + type BlacklistOrigin = EnsureRoot; + // Any single technical committee member may veto a coming council proposal, however they can + // only do it once and it lasts only for the cooloff period. + type VetoOrigin = pallet_collective::EnsureMember; + type CooloffPeriod = CooloffPeriod; + type Slash = Treasury; + type Scheduler = Scheduler; + type MaxVotes = ConstU32<100>; + type PalletsOrigin = OriginCaller; + type WeightInfo = pallet_democracy::weights::SubstrateWeight; + type MaxProposals = ConstU32<100>; + type Preimages = Preimage; + type MaxDeposits = ConstU32<100>; + type MaxBlacklisted = ConstU32<100>; +} + +parameter_types! { + pub const MinVestedTransfer: Balance = 1 * AST; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); +} + +impl pallet_vesting::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type BlockNumberToBalance = ConvertInto; + type MinVestedTransfer = MinVestedTransfer; + type WeightInfo = pallet_vesting::weights::SubstrateWeight; + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the + // highest number of schedules that encodes less than 2^10. + const MAX_VESTING_SCHEDULES: u32 = 28; +} + +parameter_types! { + pub const DepositPerItem: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); + // Fallback value if storage deposit limit not set by the user + pub const DefaultDepositLimit: Balance = deposit(16, 16 * 1024); + pub Schedule: pallet_contracts::Schedule = Default::default(); +} + +impl pallet_contracts::Config for Runtime { + type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + /// The safest default is to allow no calls at all. + /// + /// Runtimes should whitelist dispatchables that are allowed to be called from contracts + /// and make sure they are stable. Dispatchables exposed to contracts are not allowed to + /// change because that would break already deployed contracts. The `Call` structure itself + /// is not allowed to change the indices of existing pallets, too. + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type DefaultDepositLimit = DefaultDepositLimit; + type CallStack = [pallet_contracts::Frame; 5]; + type WeightPrice = pallet_transaction_payment::Pallet; + type WeightInfo = pallet_contracts::weights::SubstrateWeight; + type ChainExtension = ( + DappsStakingExtension, + XvmExtension, + AssetsExtension>, + ); + type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = pallet_sudo::weights::SubstrateWeight; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Allows all runtime calls for proxy account + Any, + /// Allows only NonTransfer runtime calls for proxy account + /// To know exact calls check InstanceFilter implementation for ProxyTypes + NonTransfer, + /// All Runtime calls from Pallet Balances allowed for proxy account + Balances, + /// All Runtime calls from Pallet Assets allowed for proxy account + Assets, + /// Only Runtime Calls related to goverance 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, + /// Only claim_staker call from pallet DappStaking allowed for proxy account + StakerRewardClaim, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + // Always allowed RuntimeCall::Utility no matter type. + // Only transactions allowed by Proxy.filter can be executed + _ if matches!(c, RuntimeCall::Utility(..)) => true, + // Allows all runtime calls for proxy account + ProxyType::Any => true, + // Allows only NonTransfer runtime calls for proxy account + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::Scheduler(..) + | RuntimeCall::Proxy(..) + | RuntimeCall::Grandpa(..) + // Skip entire Balances pallet + | RuntimeCall::Vesting(pallet_vesting::Call::vest{..}) + | RuntimeCall::Vesting(pallet_vesting::Call::vest_other{..}) + // Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer` + | RuntimeCall::DappsStaking(..) + // Skip entire EVM pallet + // Skip entire Ethereum pallet + // Skip entire EthCall pallet + | RuntimeCall::BaseFee(..) + // Skip entire Contracts pallet + | RuntimeCall::Democracy(..) + | RuntimeCall::Council(..) + | RuntimeCall::TechnicalCommittee(..) + | RuntimeCall::Treasury(..) + ) + } + // All Runtime calls from Pallet Balances allowed for proxy account + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..)) + } + // All Runtime calls from Pallet Assets allowed for proxy account + ProxyType::Assets => { + matches!(c, RuntimeCall::Assets(..)) + } + ProxyType::Governance => { + matches!( + c, + RuntimeCall::Democracy(..) + | RuntimeCall::Council(..) + | RuntimeCall::TechnicalCommittee(..) + | RuntimeCall::Treasury(..) + ) + } + // Only reject_announcement call from pallet proxy allowed for proxy account + ProxyType::CancelProxy => { + matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ) + } + // All runtime calls from pallet DappStaking allowed for proxy account + ProxyType::DappsStaking => { + matches!(c, RuntimeCall::DappsStaking(..)) + } + ProxyType::StakerRewardClaim => { + matches!( + c, + RuntimeCall::DappsStaking(pallet_dapps_staking::Call::claim_staker { .. }) + ) + } + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::NonTransfer, _) => true, + (ProxyType::DappsStaking, ProxyType::StakerRewardClaim) => true, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8; . + type ProxyDepositBase = ConstU128<{ AST * 10 }>; + // Additional storage item size of 33 bytes. + type ProxyDepositFactor = ConstU128<{ MILLIAST * 330 }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + // Key size 32 + 1 item + type AnnouncementDepositBase = ConstU128<{ AST * 10 }>; + // Acc Id + Hash + block number + type AnnouncementDepositFactor = ConstU128<{ MILLIAST * 660 }>; +} + +// TODO: remove this once https://github.com/paritytech/substrate/issues/12161 is resolved +#[rustfmt::skip] +construct_runtime!( + pub struct Runtime + where + Block = Block, + NodeBlock = generic::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Utility: pallet_utility, + Timestamp: pallet_timestamp, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, + Aura: pallet_aura, + Grandpa: pallet_grandpa, + Balances: pallet_balances, + Vesting: pallet_vesting, + DappsStaking: pallet_dapps_staking, + DappStaking: pallet_dapp_staking_v3, + BlockReward: pallet_block_reward, + Inflation: pallet_inflation, + TransactionPayment: pallet_transaction_payment, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthCall: pallet_custom_signatures, + BaseFee: pallet_base_fee, + Contracts: pallet_contracts, + Sudo: pallet_sudo, + Assets: pallet_assets, + Scheduler: pallet_scheduler, + Democracy: pallet_democracy, + Council: pallet_collective::, + TechnicalCommittee: pallet_collective::, + Treasury: pallet_treasury, + Xvm: pallet_xvm, + Proxy: pallet_proxy, + Preimage: pallet_preimage, + EthereumChecked: pallet_ethereum_checked, + } +); + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// The payload being signed in transactions. +pub type SignedPayload = generic::SignedPayload; +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +type EventRecord = frame_system::EventRecord< + ::RuntimeEvent, + ::Hash, +>; + +impl fp_self_contained::SelfContainedCall for RuntimeCall { + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + fn check_self_contained(&self) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => { + call.pre_dispatch_self_contained(info, dispatch_info, len) + } + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { + Some(call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info), + ))) + } + _ => None, + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_benchmarking, BaselineBench::] + [pallet_assets, Assets] + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_timestamp, Timestamp] + [pallet_dapps_staking, DappsStaking] + [pallet_block_reward, BlockReward] + [pallet_ethereum_checked, EthereumChecked] + [pallet_dapp_staking_v3, DappStaking] + [pallet_inflation, Inflation] + ); +} + +impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block); + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> GrandpaAuthorityList { + Grandpa::grandpa_authorities() + } + + fn current_set_id() -> fg_primitives::SetId { + Grandpa::current_set_id() + } + + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: fg_primitives::EquivocationProof< + ::Hash, + NumberFor, + >, + _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + + fn generate_key_ownership_proof( + _set_id: fg_primitives::SetId, + _authority_id: GrandpaId, + ) -> Option { + // NOTE: this is the only implementation possible since we've + // defined our key owner proof type as a bottom type (i.e. a type + // with no values). + None + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl fp_rpc::EthereumRuntimeRPCApi for Runtime { + fn chain_id() -> u64 { + ChainId::get() + } + + fn account_basic(address: H160) -> pallet_evm::Account { + let (account, _) = EVM::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(address) + } + + fn author() -> H160 { + >::find_author() + } + + fn storage_at(address: H160, index: U256) -> H256 { + let mut tmp = [0u8; 32]; + index.to_big_endian(&mut tmp); + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) + } + + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + let validate = true; + + // Reused approach from Moonbeam since Frontier implementation doesn't support this + let mut estimated_transaction_len = data.len() + + // to: 20 + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 210; + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + Vec::new(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config + .as_ref() + .unwrap_or_else(|| ::config()), + ) + .map_err(|err| err.error.into()) + } + + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + let validate = true; + + // Reused approach from Moonbeam since Frontier implementation doesn't support this + let mut estimated_transaction_len = data.len() + + // to: 20 + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 210; + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + #[allow(clippy::or_fun_call)] // suggestion not helpful here + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + Vec::new(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config + .as_ref() + .unwrap_or(::config()), + ) + .map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option>, + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn extrinsic_filter( + xts: Vec<::Extrinsic>, + ) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), + _ => None + }).collect::>() + } + + fn elasticity() -> Option { + Some(pallet_base_fee::Elasticity::::get()) + } + + fn gas_limit_multiplier_support() {} + + fn pending_block( + xts: Vec<::Extrinsic>, + ) -> (Option, Option>) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } + + Ethereum::on_finalize(System::block_number() + 1); + + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction( + transaction: pallet_ethereum::Transaction + ) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } + + impl pallet_contracts::ContractsApi for Runtime { + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + input_data: Vec, + ) -> pallet_contracts_primitives::ContractExecResult { + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit, + input_data, + pallet_contracts::DebugInfo::UnsafeDebug, + pallet_contracts::CollectEvents::UnsafeCollect, + pallet_contracts::Determinism::Enforced, + ) + } + + fn instantiate( + origin: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + code: pallet_contracts_primitives::Code, + data: Vec, + salt: Vec, + ) -> pallet_contracts_primitives::ContractInstantiateResult { + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_instantiate( + origin, + value, + gas_limit, + storage_deposit_limit, + code, + data, + salt, + pallet_contracts::DebugInfo::UnsafeDebug, + pallet_contracts::CollectEvents::UnsafeCollect, + ) + } + + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + determinism: pallet_contracts::Determinism, + ) -> pallet_contracts_primitives::CodeUploadResult + { + Contracts::bare_upload_code(origin, code, storage_deposit_limit, determinism) + } + + fn get_storage( + address: AccountId, + key: Vec, + ) -> pallet_contracts_primitives::GetStorageResult { + Contracts::get_storage(address, key) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; + use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; + + impl frame_system_benchmarking::Config for Runtime {} + impl baseline::Config for Runtime {} + + use frame_support::traits::WhitelistedStorageKeys; + let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + + #[cfg(feature = "evm-tracing")] + impl moonbeam_rpc_primitives_debug::DebugRuntimeApi for Runtime { + fn trace_transaction( + extrinsics: Vec<::Extrinsic>, + traced_transaction: &pallet_ethereum::Transaction, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + use moonbeam_evm_tracer::tracer::EvmTracer; + + // Apply the a subset of extrinsics: all the substrate-specific or ethereum + // transactions that preceded the requested transaction. + for ext in extrinsics.into_iter() { + let _ = match &ext.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => { + if transaction == traced_transaction { + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + return Ok(()); + } else { + Executive::apply_extrinsic(ext) + } + } + _ => Executive::apply_extrinsic(ext), + }; + } + Err(sp_runtime::DispatchError::Other( + "Failed to find Ethereum transaction among the extrinsics.", + )) + } + + fn trace_block( + extrinsics: Vec<::Extrinsic>, + known_transactions: Vec, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + use moonbeam_evm_tracer::tracer::EvmTracer; + + let mut config = ::config().clone(); + config.estimate = true; + + // Apply all extrinsics. Ethereum extrinsics are traced. + for ext in extrinsics.into_iter() { + match &ext.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => { + if known_transactions.contains(&transaction.hash()) { + // Each known extrinsic is a new call stack. + EvmTracer::emit_new(); + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + } else { + let _ = Executive::apply_extrinsic(ext); + } + } + _ => { + let _ = Executive::apply_extrinsic(ext); + } + }; + } + + Ok(()) + } + } + + #[cfg(feature = "evm-tracing")] + impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi for Runtime { + fn extrinsic_filter( + xts_ready: Vec<::Extrinsic>, + xts_future: Vec<::Extrinsic>, + ) -> moonbeam_rpc_primitives_txpool::TxPoolResponse { + moonbeam_rpc_primitives_txpool::TxPoolResponse { + ready: xts_ready + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + future: xts_future + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + } + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade"); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + log::info!( + "try-runtime: executing block #{} ({:?}) / root checks: {:?} / sanity-checks: {:?}", + block.header.number, + block.header.hash(), + state_root_check, + select, + ); + Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") + } + } +} From 7263d1781b9dfc408660facd877131d1c4cb1156 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Thu, 30 Nov 2023 17:27:30 +0100 Subject: [PATCH 05/30] remove orig file --- runtime/local/src/lib.rs.orig | 1893 --------------------------------- 1 file changed, 1893 deletions(-) delete mode 100644 runtime/local/src/lib.rs.orig diff --git a/runtime/local/src/lib.rs.orig b/runtime/local/src/lib.rs.orig deleted file mode 100644 index 779261f6ef..0000000000 --- a/runtime/local/src/lib.rs.orig +++ /dev/null @@ -1,1893 +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 . - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -use frame_support::{ - construct_runtime, parameter_types, - traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Currency, EitherOfDiverse, - EqualPrivilegeOnly, FindAuthor, Get, InstanceFilter, Nothing, OnFinalize, WithdrawReasons, - }, - weights::{ - constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, - ConstantMultiplier, IdentityFee, Weight, - }, - ConsensusEngineId, PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, -}; -use pallet_ethereum::PostLogContent; -use pallet_evm::{FeeCalculator, GasWeightMapping, Runner}; -use pallet_evm_precompile_assets_erc20::AddressToAssetId; -use pallet_grandpa::{fg_primitives, AuthorityList as GrandpaAuthorityList}; -use parity_scale_codec::{Compact, Decode, Encode, MaxEncodedLen}; -use sp_api::impl_runtime_apis; -use sp_arithmetic::fixed_point::FixedU64; -use sp_core::{crypto::KeyTypeId, ConstBool, OpaqueMetadata, H160, H256, U256}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{ - AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, - DispatchInfoOf, Dispatchable, NumberFor, PostDispatchInfoOf, UniqueSaturatedInto, Verify, - }, - transaction_validity::{ - TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, - }, - ApplyExtrinsicResult, RuntimeDebug, -}; -use sp_std::prelude::*; - -pub use astar_primitives::{ - evm::EvmRevertCodeHandler, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, - Index, Signature, -}; - -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -pub use frame_system::Call as SystemCall; -pub use pallet_balances::Call as BalancesCall; -pub use pallet_grandpa::AuthorityId as GrandpaId; -pub use pallet_inflation::InflationParameters; -pub use pallet_timestamp::Call as TimestampCall; -use pallet_transaction_payment::CurrencyAdapter; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; -pub use sp_runtime::{Perbill, Permill}; - -#[cfg(feature = "std")] -/// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics. -pub fn wasm_binary_unwrap() -> &'static [u8] { - WASM_BINARY.expect( - "Development wasm binary is not available. This means the client is \ - built with `BUILD_DUMMY_WASM_BINARY` flag and it is only usable for \ - production chains. Please rebuild with the flag disabled.", - ) -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("local"), - impl_name: create_runtime_str!("local"), - authoring_version: 1, - spec_version: 1, - impl_version: 1, - apis: RUNTIME_API_VERSIONS, - transaction_version: 1, - state_version: 1, -}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - pub grandpa: Grandpa, - } -} - -mod precompiles; -pub use precompiles::{LocalNetworkPrecompiles, ASSET_PRECOMPILE_ADDRESS_PREFIX}; -pub type Precompiles = LocalNetworkPrecompiles; - -mod chain_extensions; -pub use chain_extensions::*; - -mod weights; - -/// Constant values used within the runtime. -pub const MICROAST: Balance = 1_000_000_000_000; -pub const MILLIAST: Balance = 1_000 * MICROAST; -pub const AST: Balance = 1_000 * MILLIAST; - -pub const STORAGE_BYTE_FEE: Balance = 100 * MICROAST; - -/// Charge fee for stored bytes and items. -pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 1 * AST + (bytes as Balance) * STORAGE_BYTE_FEE -} - -/// This determines the average expected block time that we are targeting. -/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. -/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked -/// up by `pallet_aura` to implement `fn slot_duration()`. -/// -/// Change this to adjust the block time. -pub const MILLISECS_PER_BLOCK: u64 = 2000; -pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; - -// Time is measured by number of blocks. -pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; - -impl AddressToAssetId for Runtime { - fn address_to_asset_id(address: H160) -> Option { - let mut data = [0u8; 16]; - let address_bytes: [u8; 20] = address.into(); - if ASSET_PRECOMPILE_ADDRESS_PREFIX.eq(&address_bytes[0..4]) { - data.copy_from_slice(&address_bytes[4..20]); - Some(u128::from_be_bytes(data)) - } else { - None - } - } - - fn asset_id_to_address(asset_id: AssetId) -> H160 { - let mut data = [0u8; 20]; - data[0..4].copy_from_slice(ASSET_PRECOMPILE_ADDRESS_PREFIX); - data[4..20].copy_from_slice(&asset_id.to_be_bytes()); - H160::from(data) - } -} - -/// The version information used to identify this runtime when compiled natively. -#[cfg(feature = "std")] -pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } -} - -/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used -/// by Operational extrinsics. -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); - -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - pub const BlockHashCount: BlockNumber = 2400; - /// We allow for 1 seconds of compute with a 2 second average block time. - pub RuntimeBlockWeights: BlockWeights = BlockWeights - ::with_sensible_defaults(Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX), NORMAL_DISPATCH_RATIO); - pub RuntimeBlockLength: BlockLength = BlockLength - ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub const SS58Prefix: u8 = 5; -} - -// Configure FRAME pallets to include in runtime. - -impl frame_system::Config for Runtime { - /// The basic call filter to use in dispatchable. - type BaseCallFilter = frame_support::traits::Everything; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - /// The index type for storing how many extrinsics an account has signed. - type Index = Index; - /// The index type for blocks. - type BlockNumber = BlockNumber; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The hashing algorithm used. - type Hashing = BlakeTwo256; - /// The header type. - type Header = generic::Header; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// Version of the runtime. - type Version = Version; - /// Converts a module to the index of the module in `construct_runtime!`. - /// - /// This type is being generated by `construct_runtime!`. - type PalletInfo = PalletInfo; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = frame_system::weights::SubstrateWeight; - /// This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - /// The set code logic, just the default since we're not a parachain. - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const MaxAuthorities: u32 = 50; -} - -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<50>; -} - -impl pallet_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - - type KeyOwnerProof = sp_core::Void; - type EquivocationReportSystem = (); - - type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; - type MaxSetIdSessionEntries = ConstU64<0>; -} - -parameter_types! { - pub const MinimumPeriod: u64 = SLOT_DURATION / 2; -} - -impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. - type Moment = u64; - type OnTimestampSet = (Aura, BlockReward); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = pallet_timestamp::weights::SubstrateWeight; -} - -impl pallet_insecure_randomness_collective_flip::Config for Runtime {} - -parameter_types! { - pub const ExistentialDeposit: u128 = 500; - pub const MaxLocks: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = MaxLocks; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - /// The type for recording an account's balance. - type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type HoldIdentifier = (); - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - pub const AssetDeposit: Balance = 1 * AST; - pub const AssetsStringLimit: u32 = 50; - /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) - // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 - pub const MetadataDepositBase: Balance = deposit(1, 68); - pub const MetadataDepositPerByte: Balance = deposit(0, 1); - pub const AssetAccountDeposit: Balance = deposit(1, 18); -} - -impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = AssetId; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type AssetAccountDeposit = AssetAccountDeposit; - type ApprovalDeposit = ExistentialDeposit; - type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); - type WeightInfo = weights::pallet_assets::SubstrateWeight; - type RemoveItemsLimit = ConstU32<1000>; - type AssetIdParameter = Compact; - type CallbackHandle = EvmRevertCodeHandler; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = astar_primitives::benchmarks::AssetsBenchmarkHelper; -} - -parameter_types! { - pub const TransactionByteFee: Balance = 1; - pub const OperationalFeeMultiplier: u8 = 5; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - type WeightToFee = IdentityFee; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type FeeMultiplierUpdate = (); - type LengthToFee = ConstantMultiplier; -} - -parameter_types! { - pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const DappsStakingPalletId: PalletId = PalletId(*b"py/dpsst"); -} - -type NegativeImbalance = >::NegativeImbalance; - -pub struct DappsStakingTvlProvider(); -impl Get for DappsStakingTvlProvider { - fn get() -> Balance { - DappsStaking::tvl() - } -} - -pub struct BeneficiaryPayout(); -impl pallet_block_reward::BeneficiaryPayout for BeneficiaryPayout { - fn treasury(reward: NegativeImbalance) { - Balances::resolve_creating(&TreasuryPalletId::get().into_account_truncating(), reward); - } - - fn collators(_reward: NegativeImbalance) { - // no collators for local dev node - } - - fn dapps_staking(stakers: NegativeImbalance, dapps: NegativeImbalance) { - DappsStaking::rewards(stakers, dapps) - } -} - -parameter_types! { - pub const RewardAmount: Balance = 2_664 * MILLIAST; -} - -impl pallet_block_reward::Config for Runtime { - type Currency = Balances; - type DappsStakingTvlProvider = DappsStakingTvlProvider; - type BeneficiaryPayout = BeneficiaryPayout; - type RewardAmount = RewardAmount; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_block_reward::weights::SubstrateWeight; -} - -parameter_types! { - pub const BlockPerEra: BlockNumber = 60; - pub const RegisterDeposit: Balance = 100 * AST; - pub const MaxNumberOfStakersPerContract: u32 = 512; - pub const MinimumStakingAmount: Balance = 10 * AST; - pub const MinimumRemainingAmount: Balance = AST; - pub const MaxUnlockingChunks: u32 = 2; - pub const UnbondingPeriod: u32 = 2; - pub const MaxEraStakeValues: u32 = 5; -} - -impl pallet_dapps_staking::Config for Runtime { - type Currency = Balances; - type BlockPerEra = BlockPerEra; - type SmartContract = SmartContract; - type RegisterDeposit = RegisterDeposit; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_dapps_staking::weights::SubstrateWeight; - type MaxNumberOfStakersPerContract = MaxNumberOfStakersPerContract; - type MinimumStakingAmount = MinimumStakingAmount; - type PalletId = DappsStakingPalletId; - type MaxUnlockingChunks = MaxUnlockingChunks; - type UnbondingPeriod = UnbondingPeriod; - type MinimumRemainingAmount = MinimumRemainingAmount; - type MaxEraStakeValues = MaxEraStakeValues; - type UnregisteredDappRewardRetention = ConstU32<3>; -} - -/// Multi-VM pointer to smart contract instance. -#[derive( - PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, -)] -pub enum SmartContract { - /// EVM smart contract instance. - Evm(sp_core::H160), - /// Wasm smart contract instance. - Wasm(AccountId), -} - -impl Default for SmartContract { - fn default() -> Self { - SmartContract::Evm(H160::repeat_byte(0x00)) - } -} - -impl> From<[u8; 32]> for SmartContract { - fn from(input: [u8; 32]) -> Self { - SmartContract::Wasm(input.into()) - } -} - -pub struct DummyPriceProvider; -impl pallet_dapp_staking_v3::PriceProvider for DummyPriceProvider { - fn average_price() -> FixedU64 { - FixedU64::from_rational(1, 10) - } -} - -pub struct DummyRewardPoolProvider; -impl pallet_dapp_staking_v3::RewardPoolProvider for DummyRewardPoolProvider { - fn normal_reward_pools() -> (Balance, Balance) { - ( - Balance::from(1_000_000_000_000 * AST), - Balance::from(1_000_000_000 * AST), - ) - } - fn bonus_reward_pool() -> Balance { - Balance::from(3_000_000 * AST) - } -} - -#[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkHelper(sp_std::marker::PhantomData); -#[cfg(feature = "runtime-benchmarks")] -impl pallet_dapp_staking_v3::BenchmarkHelper> - for BenchmarkHelper> -{ - fn get_smart_contract(id: u32) -> SmartContract { - SmartContract::Wasm(AccountId::from([id as u8; 32])) - } -} - -parameter_types! { - pub const StandardEraLength: BlockNumber = 30; // should be 1 minute per standard era - pub const StandardErasPerVotingSubperiod: u32 = 2; - pub const StandardErasPerBuildAndEarnSubperiod: u32 = 10; -} - -impl pallet_dapp_staking_v3::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type SmartContract = SmartContract; - type ManagerOrigin = frame_system::EnsureRoot; - type NativePriceProvider = DummyPriceProvider; - type RewardPoolProvider = DummyRewardPoolProvider; -<<<<<<< HEAD - type StandardEraLength = ConstU32<30>; // should be 1 minute per standard era - type StandardErasPerVotingSubperiod = ConstU32<2>; - type StandardErasPerBuildAndEarnSubperiod = ConstU32<22>; -======= - type StandardEraLength = StandardEraLength; - type StandardErasPerVotingSubperiod = StandardErasPerVotingSubperiod; - type StandardErasPerBuildAndEarnSubperiod = StandardErasPerBuildAndEarnSubperiod; ->>>>>>> origin/feat/dapp-staking-v3 - type EraRewardSpanLength = ConstU32<8>; - type RewardRetentionInPeriods = ConstU32<2>; - type MaxNumberOfContracts = ConstU32<100>; - type MaxUnlockingChunks = ConstU32<5>; - type MinimumLockedAmount = ConstU128; - type UnlockingPeriod = ConstU32<2>; - type MaxNumberOfStakedContracts = ConstU32<3>; - type MinimumStakeAmount = ConstU128; - type NumberOfTiers = ConstU32<4>; - type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = BenchmarkHelper>; -} - -pub struct InflationPayoutPerBlock; -impl pallet_inflation::PayoutPerBlock for InflationPayoutPerBlock { - fn treasury(reward: NegativeImbalance) { - Balances::resolve_creating(&TreasuryPalletId::get().into_account_truncating(), reward); - } - - fn collators(_reward: NegativeImbalance) { - // no collators for local dev node - } -} - -pub struct InflationCycleConfig; -impl pallet_inflation::CycleConfiguration for InflationCycleConfig { - fn periods_per_cycle() -> u32 { - 4 - } - - fn eras_per_voting_subperiod() -> u32 { - StandardErasPerVotingSubperiod::get() - } - - fn eras_per_build_and_earn_subperiod() -> u32 { - StandardErasPerBuildAndEarnSubperiod::get() - } - - fn blocks_per_era() -> u32 { - StandardEraLength::get() - } -} - -impl pallet_inflation::Config for Runtime { - type Currency = Balances; - type PayoutPerBlock = InflationPayoutPerBlock; - type CycleConfiguration = InflationCycleConfig; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_inflation::weights::SubstrateWeight; -} - -impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; -} - -///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { - fn into_h160(account_id: AccountId) -> H160 { - let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); - } -} - -parameter_types! { - /// Equal to normal class dispatch weight limit. - pub XvmTxWeightLimit: Weight = NORMAL_DISPATCH_RATIO * Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX); - pub ReservedXcmpWeight: Weight = Weight::zero(); -} - -impl pallet_ethereum_checked::Config for Runtime { - type ReservedXcmpWeight = ReservedXcmpWeight; - type XvmTxWeightLimit = XvmTxWeightLimit; - type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; - type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; - type AccountMapping = HashedAccountMapping; - type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; - type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; -} - -impl pallet_xvm::Config for Runtime { - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type AccountMapping = HashedAccountMapping; - type EthereumTransact = EthereumChecked; - type WeightInfo = pallet_xvm::weights::SubstrateWeight; -} - -parameter_types! { - // Tells `pallet_base_fee` whether to calculate a new BaseFee `on_finalize` or not. - pub DefaultBaseFeePerGas: U256 = (MILLIAST / 1_000_000).into(); - // At the moment, we don't use dynamic fee calculation for local chain by default - pub DefaultElasticity: Permill = Permill::zero(); -} - -pub struct BaseFeeThreshold; -impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold { - fn lower() -> Permill { - Permill::zero() - } - fn ideal() -> Permill { - Permill::from_parts(500_000) - } - fn upper() -> Permill { - Permill::from_parts(1_000_000) - } -} - -impl pallet_base_fee::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Threshold = BaseFeeThreshold; - type DefaultBaseFeePerGas = DefaultBaseFeePerGas; - type DefaultElasticity = DefaultElasticity; -} - -/// Current approximation of the gas/s consumption considering -/// EVM execution over compiled WASM (on 4.4Ghz CPU). -/// Given the 500ms Weight, from which 75% only are used for transactions, -/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000. -pub const GAS_PER_SECOND: u64 = 40_000_000; - -/// Approximate ratio of the amount of Weight per Gas. -/// u64 works for approximations because Weight is a very small unit compared to gas. -pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND.saturating_div(GAS_PER_SECOND); - -pub struct FindAuthorTruncated(sp_std::marker::PhantomData); -impl> FindAuthor for FindAuthorTruncated { - fn find_author<'a, I>(digests: I) -> Option - where - I: 'a + IntoIterator, - { - if let Some(author_index) = F::find_author(digests) { - let authority_id = Aura::authorities()[author_index as usize].clone(); - return Some(H160::from_slice(&authority_id.encode()[4..24])); - } - - None - } -} - -parameter_types! { - /// Ethereum-compatible chain_id: - /// * Dusty: 80 - /// * Shibuya: 81 - /// * Shiden: 336 - /// * Local: 4369 - pub ChainId: u64 = 0x1111; - /// EVM gas limit - pub BlockGasLimit: U256 = U256::from( - NORMAL_DISPATCH_RATIO * WEIGHT_REF_TIME_PER_SECOND / WEIGHT_PER_GAS - ); - pub PrecompilesValue: Precompiles = LocalNetworkPrecompiles::<_>::new(); - pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); - /// The amount of gas per PoV size. Value is calculated as: - /// - /// max_gas_limit = max_tx_ref_time / WEIGHT_PER_GAS = max_pov_size * gas_limit_pov_size_ratio - /// gas_limit_pov_size_ratio = ceil((max_tx_ref_time / WEIGHT_PER_GAS) / max_pov_size) - /// - /// Local runtime has no strict bounds as parachain, but we keep the value set to 4 for consistency. - pub const GasLimitPovSizeRatio: u64 = 4; -} - -impl pallet_evm::Config for Runtime { - type FeeCalculator = BaseFee; - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type WeightPerGas = WeightPerGas; - type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; - type CallOrigin = pallet_evm::EnsureAddressRoot; - type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; - type AddressMapping = pallet_evm::HashedAddressMapping; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type Runner = pallet_evm::runner::stack::Runner; - type PrecompilesType = Precompiles; - type PrecompilesValue = PrecompilesValue; - type ChainId = ChainId; - type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; - type BlockGasLimit = BlockGasLimit; - type Timestamp = Timestamp; - type OnCreate = (); - type FindAuthor = FindAuthorTruncated; - type GasLimitPovSizeRatio = GasLimitPovSizeRatio; - type WeightInfo = pallet_evm::weights::SubstrateWeight; -} - -parameter_types! { - pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; -} - -impl pallet_ethereum::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type StateRoot = pallet_ethereum::IntermediateStateRoot; - type PostLogContent = PostBlockAndTxnHashes; - // Maximum length (in bytes) of revert message to include in Executed event - type ExtraDataLength = ConstU32<30>; -} - -parameter_types! { - pub const EcdsaUnsignedPriority: TransactionPriority = TransactionPriority::MAX / 2; - pub const CallFee: Balance = AST / 10; - pub const CallMagicNumber: u16 = 0xff51; -} - -impl pallet_custom_signatures::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Signature = pallet_custom_signatures::ethereum::EthereumSignature; - type Signer = ::Signer; - type CallMagicNumber = CallMagicNumber; - type Currency = Balances; - type CallFee = CallFee; - type OnChargeTransaction = (); - type UnsignedPriority = EcdsaUnsignedPriority; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; -} - -impl pallet_scheduler::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = ConstU32<50>; - type WeightInfo = pallet_scheduler::weights::SubstrateWeight; - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = Preimage; -} - -parameter_types! { - pub const PreimageBaseDeposit: Balance = deposit(1, 0); - pub const PreimageByteDeposit: Balance = deposit(0, 1); -} - -impl pallet_preimage::Config for Runtime { - type WeightInfo = pallet_preimage::weights::SubstrateWeight; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; -} - -parameter_types! { - pub CouncilMotionDuration: BlockNumber = 3 * MINUTES; - pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; -} - -type CouncilCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type Proposal = RuntimeCall; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = ConstU32<100>; - type MaxMembers = ConstU32<3>; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type SetMembersOrigin = EnsureRoot; - type MaxProposalWeight = MaxProposalWeight; -} - -parameter_types! { - pub const TechnicalCommitteeMotionDuration: BlockNumber = 3 * MINUTES; -} - -type TechnicalCommitteeCollective = pallet_collective::Instance2; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type Proposal = RuntimeCall; - type MotionDuration = TechnicalCommitteeMotionDuration; - type MaxProposals = ConstU32<100>; - type MaxMembers = ConstU32<3>; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type SetMembersOrigin = EnsureRoot; - type MaxProposalWeight = MaxProposalWeight; -} - -parameter_types! { - pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: Balance = 100 * AST; - pub const ProposalBondMaximum: Balance = 500 * AST; - pub const SpendPeriod: BlockNumber = 1 * MINUTES; - pub const Burn: Permill = Permill::from_percent(1); -} - -impl pallet_treasury::Config for Runtime { - type PalletId = TreasuryPalletId; - type Currency = Balances; - type ApproveOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type RejectOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, - >; - type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; - type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type ProposalBondMaximum = ProposalBondMaximum; - type SpendPeriod = SpendPeriod; - type Burn = Burn; - type BurnDestination = (); - type SpendFunds = (); - type MaxApprovals = ConstU32<100>; - type WeightInfo = pallet_treasury::weights::SubstrateWeight; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; -} - -parameter_types! { - pub LaunchPeriod: BlockNumber = 1 * MINUTES; - pub VotingPeriod: BlockNumber = 3 * MINUTES; - pub FastTrackVotingPeriod: BlockNumber = 1 * MINUTES; - pub const MinimumDeposit: Balance = 7000 * AST; - pub EnactmentPeriod: BlockNumber = 5 * MINUTES; - pub VoteLockingPeriod: BlockNumber = 10 * MINUTES; - pub CooloffPeriod: BlockNumber = 10 * MINUTES; - pub const InstantAllowed: bool = true; -} - -impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = VoteLockingPeriod; - type MinimumDeposit = MinimumDeposit; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - /// A 60% super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - type SubmitOrigin = EnsureSigned; - /// Two thirds of the technical committee can have an `ExternalMajority/ExternalDefault` vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - type InstantOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - type InstantAllowed = InstantAllowed; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - type BlacklistOrigin = EnsureRoot; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cooloff period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type MaxVotes = ConstU32<100>; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_democracy::weights::SubstrateWeight; - type MaxProposals = ConstU32<100>; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; -} - -parameter_types! { - pub const MinVestedTransfer: Balance = 1 * AST; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); -} - -impl pallet_vesting::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BlockNumberToBalance = ConvertInto; - type MinVestedTransfer = MinVestedTransfer; - type WeightInfo = pallet_vesting::weights::SubstrateWeight; - type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the - // highest number of schedules that encodes less than 2^10. - const MAX_VESTING_SCHEDULES: u32 = 28; -} - -parameter_types! { - pub const DepositPerItem: Balance = deposit(1, 0); - pub const DepositPerByte: Balance = deposit(0, 1); - // Fallback value if storage deposit limit not set by the user - pub const DefaultDepositLimit: Balance = deposit(16, 16 * 1024); - pub Schedule: pallet_contracts::Schedule = Default::default(); -} - -impl pallet_contracts::Config for Runtime { - type Time = Timestamp; - type Randomness = RandomnessCollectiveFlip; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - /// The safest default is to allow no calls at all. - /// - /// Runtimes should whitelist dispatchables that are allowed to be called from contracts - /// and make sure they are stable. Dispatchables exposed to contracts are not allowed to - /// change because that would break already deployed contracts. The `Call` structure itself - /// is not allowed to change the indices of existing pallets, too. - type CallFilter = Nothing; - type DepositPerItem = DepositPerItem; - type DepositPerByte = DepositPerByte; - type DefaultDepositLimit = DefaultDepositLimit; - type CallStack = [pallet_contracts::Frame; 5]; - type WeightPrice = pallet_transaction_payment::Pallet; - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = ( - DappsStakingExtension, - XvmExtension, - AssetsExtension>, - ); - type Schedule = Schedule; - type AddressGenerator = pallet_contracts::DefaultAddressGenerator; - type MaxCodeLen = ConstU32<{ 123 * 1024 }>; - type MaxStorageKeyLen = ConstU32<128>; - type UnsafeUnstableInterface = ConstBool; - type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type WeightInfo = pallet_sudo::weights::SubstrateWeight; -} - -/// The type used to represent the kinds of proxying allowed. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - /// Allows all runtime calls for proxy account - Any, - /// Allows only NonTransfer runtime calls for proxy account - /// To know exact calls check InstanceFilter implementation for ProxyTypes - NonTransfer, - /// All Runtime calls from Pallet Balances allowed for proxy account - Balances, - /// All Runtime calls from Pallet Assets allowed for proxy account - Assets, - /// Only Runtime Calls related to goverance 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, - /// Only claim_staker call from pallet DappStaking allowed for proxy account - StakerRewardClaim, -} - -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} - -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - // Always allowed RuntimeCall::Utility no matter type. - // Only transactions allowed by Proxy.filter can be executed - _ if matches!(c, RuntimeCall::Utility(..)) => true, - // Allows all runtime calls for proxy account - ProxyType::Any => true, - // Allows only NonTransfer runtime calls for proxy account - ProxyType::NonTransfer => { - matches!( - c, - RuntimeCall::System(..) - | RuntimeCall::Timestamp(..) - | RuntimeCall::Scheduler(..) - | RuntimeCall::Proxy(..) - | RuntimeCall::Grandpa(..) - // Skip entire Balances pallet - | RuntimeCall::Vesting(pallet_vesting::Call::vest{..}) - | RuntimeCall::Vesting(pallet_vesting::Call::vest_other{..}) - // Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer` - | RuntimeCall::DappsStaking(..) - // Skip entire EVM pallet - // Skip entire Ethereum pallet - // Skip entire EthCall pallet - | RuntimeCall::BaseFee(..) - // Skip entire Contracts pallet - | RuntimeCall::Democracy(..) - | RuntimeCall::Council(..) - | RuntimeCall::TechnicalCommittee(..) - | RuntimeCall::Treasury(..) - ) - } - // All Runtime calls from Pallet Balances allowed for proxy account - ProxyType::Balances => { - matches!(c, RuntimeCall::Balances(..)) - } - // All Runtime calls from Pallet Assets allowed for proxy account - ProxyType::Assets => { - matches!(c, RuntimeCall::Assets(..)) - } - ProxyType::Governance => { - matches!( - c, - RuntimeCall::Democracy(..) - | RuntimeCall::Council(..) - | RuntimeCall::TechnicalCommittee(..) - | RuntimeCall::Treasury(..) - ) - } - // Only reject_announcement call from pallet proxy allowed for proxy account - ProxyType::CancelProxy => { - matches!( - c, - RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) - ) - } - // All runtime calls from pallet DappStaking allowed for proxy account - ProxyType::DappsStaking => { - matches!(c, RuntimeCall::DappsStaking(..)) - } - ProxyType::StakerRewardClaim => { - matches!( - c, - RuntimeCall::DappsStaking(pallet_dapps_staking::Call::claim_staker { .. }) - ) - } - } - } - - fn is_superset(&self, o: &Self) -> bool { - match (self, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::NonTransfer, _) => true, - (ProxyType::DappsStaking, ProxyType::StakerRewardClaim) => true, - _ => false, - } - } -} - -impl pallet_proxy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - // One storage item; key size 32, value size 8; . - type ProxyDepositBase = ConstU128<{ AST * 10 }>; - // Additional storage item size of 33 bytes. - type ProxyDepositFactor = ConstU128<{ MILLIAST * 330 }>; - type MaxProxies = ConstU32<32>; - type WeightInfo = pallet_proxy::weights::SubstrateWeight; - type MaxPending = ConstU32<32>; - type CallHasher = BlakeTwo256; - // Key size 32 + 1 item - type AnnouncementDepositBase = ConstU128<{ AST * 10 }>; - // Acc Id + Hash + block number - type AnnouncementDepositFactor = ConstU128<{ MILLIAST * 660 }>; -} - -// TODO: remove this once https://github.com/paritytech/substrate/issues/12161 is resolved -#[rustfmt::skip] -construct_runtime!( - pub struct Runtime - where - Block = Block, - NodeBlock = generic::Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - Utility: pallet_utility, - Timestamp: pallet_timestamp, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Aura: pallet_aura, - Grandpa: pallet_grandpa, - Balances: pallet_balances, - Vesting: pallet_vesting, - DappsStaking: pallet_dapps_staking, - DappStaking: pallet_dapp_staking_v3, - BlockReward: pallet_block_reward, - Inflation: pallet_inflation, - TransactionPayment: pallet_transaction_payment, - EVM: pallet_evm, - Ethereum: pallet_ethereum, - EthCall: pallet_custom_signatures, - BaseFee: pallet_base_fee, - Contracts: pallet_contracts, - Sudo: pallet_sudo, - Assets: pallet_assets, - Scheduler: pallet_scheduler, - Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, - Treasury: pallet_treasury, - Xvm: pallet_xvm, - Proxy: pallet_proxy, - Preimage: pallet_preimage, - EthereumChecked: pallet_ethereum_checked, - } -); - -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - fp_self_contained::UncheckedExtrinsic; -/// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = - fp_self_contained::CheckedExtrinsic; -/// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, ->; - -type EventRecord = frame_system::EventRecord< - ::RuntimeEvent, - ::Hash, ->; - -impl fp_self_contained::SelfContainedCall for RuntimeCall { - type SignedInfo = H160; - - fn is_self_contained(&self) -> bool { - match self { - RuntimeCall::Ethereum(call) => call.is_self_contained(), - _ => false, - } - } - - fn check_self_contained(&self) -> Option> { - match self { - RuntimeCall::Ethereum(call) => call.check_self_contained(), - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option> { - match self { - RuntimeCall::Ethereum(call) => { - call.pre_dispatch_self_contained(info, dispatch_info, len) - } - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - match self { - call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { - Some(call.dispatch(RuntimeOrigin::from( - pallet_ethereum::RawOrigin::EthereumTransaction(info), - ))) - } - _ => None, - } - } -} - -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - define_benchmarks!( - [frame_benchmarking, BaselineBench::] - [pallet_assets, Assets] - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_timestamp, Timestamp] - [pallet_dapps_staking, DappsStaking] - [pallet_block_reward, BlockReward] - [pallet_ethereum_checked, EthereumChecked] - [pallet_dapp_staking_v3, DappStaking] - [pallet_inflation, Inflation] - ); -} - -impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block); - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> sp_std::vec::Vec { - Runtime::metadata_versions() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: sp_inherents::InherentData, - ) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - Aura::authorities().into_inner() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> GrandpaAuthorityList { - Grandpa::grandpa_authorities() - } - - fn current_set_id() -> fg_primitives::SetId { - Grandpa::current_set_id() - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: fg_primitives::EquivocationProof< - ::Hash, - NumberFor, - >, - _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, - _authority_id: GrandpaId, - ) -> Option { - // NOTE: this is the only implementation possible since we've - // defined our key owner proof type as a bottom type (i.e. a type - // with no values). - None - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Index { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl fp_rpc::EthereumRuntimeRPCApi for Runtime { - fn chain_id() -> u64 { - ChainId::get() - } - - fn account_basic(address: H160) -> pallet_evm::Account { - let (account, _) = EVM::account_basic(&address); - account - } - - fn gas_price() -> U256 { - let (gas_price, _) = ::FeeCalculator::min_gas_price(); - gas_price - } - - fn account_code_at(address: H160) -> Vec { - pallet_evm::AccountCodes::::get(address) - } - - fn author() -> H160 { - >::find_author() - } - - fn storage_at(address: H160, index: U256) -> H256 { - let mut tmp = [0u8; 32]; - index.to_big_endian(&mut tmp); - pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) - } - - fn call( - from: H160, - to: H160, - data: Vec, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; - - let is_transactional = false; - let validate = true; - - // Reused approach from Moonbeam since Frontier implementation doesn't support this - let mut estimated_transaction_len = data.len() + - // to: 20 - // from: 20 - // value: 32 - // gas_limit: 32 - // nonce: 32 - // 1 byte transaction action variant - // chain id 8 bytes - // 65 bytes signature - 210; - if max_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if max_priority_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if access_list.is_some() { - estimated_transaction_len += access_list.encoded_size(); - } - - let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - ::Runner::call( - from, - to, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - Vec::new(), - is_transactional, - validate, - weight_limit, - proof_size_base_cost, - config - .as_ref() - .unwrap_or_else(|| ::config()), - ) - .map_err(|err| err.error.into()) - } - - fn create( - from: H160, - data: Vec, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; - - let is_transactional = false; - let validate = true; - - // Reused approach from Moonbeam since Frontier implementation doesn't support this - let mut estimated_transaction_len = data.len() + - // to: 20 - // from: 20 - // value: 32 - // gas_limit: 32 - // nonce: 32 - // 1 byte transaction action variant - // chain id 8 bytes - // 65 bytes signature - 210; - if max_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if max_priority_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if access_list.is_some() { - estimated_transaction_len += access_list.encoded_size(); - } - - let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - #[allow(clippy::or_fun_call)] // suggestion not helpful here - ::Runner::create( - from, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - Vec::new(), - is_transactional, - validate, - weight_limit, - proof_size_base_cost, - config - .as_ref() - .unwrap_or(::config()), - ) - .map_err(|err| err.error.into()) - } - - fn current_transaction_statuses() -> Option> { - pallet_ethereum::CurrentTransactionStatuses::::get() - } - - fn current_block() -> Option { - pallet_ethereum::CurrentBlock::::get() - } - - fn current_receipts() -> Option> { - pallet_ethereum::CurrentReceipts::::get() - } - - fn current_all() -> ( - Option, - Option>, - Option>, - ) { - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentReceipts::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get() - ) - } - - fn extrinsic_filter( - xts: Vec<::Extrinsic>, - ) -> Vec { - xts.into_iter().filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), - _ => None - }).collect::>() - } - - fn elasticity() -> Option { - Some(pallet_base_fee::Elasticity::::get()) - } - - fn gas_limit_multiplier_support() {} - - fn pending_block( - xts: Vec<::Extrinsic>, - ) -> (Option, Option>) { - for ext in xts.into_iter() { - let _ = Executive::apply_extrinsic(ext); - } - - Ethereum::on_finalize(System::block_number() + 1); - - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get() - ) - } - } - - impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction( - transaction: pallet_ethereum::Transaction - ) -> ::Extrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } - } - - impl pallet_contracts::ContractsApi for Runtime { - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: Option, - storage_deposit_limit: Option, - input_data: Vec, - ) -> pallet_contracts_primitives::ContractExecResult { - let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); - Contracts::bare_call( - origin, - dest, - value, - gas_limit, - storage_deposit_limit, - input_data, - pallet_contracts::DebugInfo::UnsafeDebug, - pallet_contracts::CollectEvents::UnsafeCollect, - pallet_contracts::Determinism::Enforced, - ) - } - - fn instantiate( - origin: AccountId, - value: Balance, - gas_limit: Option, - storage_deposit_limit: Option, - code: pallet_contracts_primitives::Code, - data: Vec, - salt: Vec, - ) -> pallet_contracts_primitives::ContractInstantiateResult { - let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); - Contracts::bare_instantiate( - origin, - value, - gas_limit, - storage_deposit_limit, - code, - data, - salt, - pallet_contracts::DebugInfo::UnsafeDebug, - pallet_contracts::CollectEvents::UnsafeCollect, - ) - } - - fn upload_code( - origin: AccountId, - code: Vec, - storage_deposit_limit: Option, - determinism: pallet_contracts::Determinism, - ) -> pallet_contracts_primitives::CodeUploadResult - { - Contracts::bare_upload_code(origin, code, storage_deposit_limit, determinism) - } - - fn get_storage( - address: AccountId, - key: Vec, - ) -> pallet_contracts_primitives::GetStorageResult { - Contracts::get_storage(address, key) - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - use frame_system_benchmarking::Pallet as SystemBench; - use baseline::Pallet as BaselineBench; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - - (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; - use frame_system_benchmarking::Pallet as SystemBench; - use baseline::Pallet as BaselineBench; - - impl frame_system_benchmarking::Config for Runtime {} - impl baseline::Config for Runtime {} - - use frame_support::traits::WhitelistedStorageKeys; - let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } - Ok(batches) - } - } - - #[cfg(feature = "evm-tracing")] - impl moonbeam_rpc_primitives_debug::DebugRuntimeApi for Runtime { - fn trace_transaction( - extrinsics: Vec<::Extrinsic>, - traced_transaction: &pallet_ethereum::Transaction, - ) -> Result< - (), - sp_runtime::DispatchError, - > { - use moonbeam_evm_tracer::tracer::EvmTracer; - - // Apply the a subset of extrinsics: all the substrate-specific or ethereum - // transactions that preceded the requested transaction. - for ext in extrinsics.into_iter() { - let _ = match &ext.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => { - if transaction == traced_transaction { - EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); - return Ok(()); - } else { - Executive::apply_extrinsic(ext) - } - } - _ => Executive::apply_extrinsic(ext), - }; - } - Err(sp_runtime::DispatchError::Other( - "Failed to find Ethereum transaction among the extrinsics.", - )) - } - - fn trace_block( - extrinsics: Vec<::Extrinsic>, - known_transactions: Vec, - ) -> Result< - (), - sp_runtime::DispatchError, - > { - use moonbeam_evm_tracer::tracer::EvmTracer; - - let mut config = ::config().clone(); - config.estimate = true; - - // Apply all extrinsics. Ethereum extrinsics are traced. - for ext in extrinsics.into_iter() { - match &ext.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => { - if known_transactions.contains(&transaction.hash()) { - // Each known extrinsic is a new call stack. - EvmTracer::emit_new(); - EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); - } else { - let _ = Executive::apply_extrinsic(ext); - } - } - _ => { - let _ = Executive::apply_extrinsic(ext); - } - }; - } - - Ok(()) - } - } - - #[cfg(feature = "evm-tracing")] - impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi for Runtime { - fn extrinsic_filter( - xts_ready: Vec<::Extrinsic>, - xts_future: Vec<::Extrinsic>, - ) -> moonbeam_rpc_primitives_txpool::TxPoolResponse { - moonbeam_rpc_primitives_txpool::TxPoolResponse { - ready: xts_ready - .into_iter() - .filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), - _ => None, - }) - .collect(), - future: xts_future - .into_iter() - .filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), - _ => None, - }) - .collect(), - } - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - log::info!("try-runtime::on_runtime_upgrade"); - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, RuntimeBlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect - ) -> Weight { - log::info!( - "try-runtime: executing block #{} ({:?}) / root checks: {:?} / sanity-checks: {:?}", - block.header.number, - block.header.hash(), - state_root_check, - select, - ); - Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") - } - } -} From f3a0eaa4d7715ff90fbe837f8a5d57498755e196 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 13:14:05 +0100 Subject: [PATCH 06/30] Minor refactoring, more benchmark code --- .../dapp-staking-v3/src/benchmarking/mod.rs | 61 ++++++++--------- .../dapp-staking-v3/src/benchmarking/utils.rs | 38 ++++++++++- pallets/dapp-staking-v3/src/lib.rs | 21 +++--- pallets/dapp-staking-v3/src/test/mock.rs | 18 ++--- .../dapp-staking-v3/src/test/testing_utils.rs | 8 ++- pallets/dapp-staking-v3/src/test/tests.rs | 2 + .../dapp-staking-v3/src/test/tests_types.rs | 66 +++++++++---------- pallets/dapp-staking-v3/src/types.rs | 41 ++++-------- 8 files changed, 137 insertions(+), 118 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index 5a439cfadf..d4d1aaa8ed 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -784,48 +784,43 @@ mod benchmarks { assert_last_event::(Event::::Force { forcing_type }.into()); } - // TODO: investigate why the PoV size is so large here, evne after removing read of `IntegratedDApps` storage. + #[benchmark] + fn on_initialize_voting_to_build_and_earn() { + initial_config::(); + + let state = ActiveProtocolState::::get(); + assert_eq!(state.subperiod(), Subperiod::Voting, "Sanity check."); + + run_to_block::(state.next_era_start - 1); + DappStaking::::on_finalize(state.next_era_start - 1); + System::::set_block_number(state.next_era_start); + + #[block] + { + DappStaking::::on_initialize(state.next_era_start); + } + + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn + ); + } + + // TODO: investigate why the PoV size is so large here, even after removing read of `IntegratedDApps` storage. // Relevant file: polkadot-sdk/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs // UPDATE: after some investigation, it seems that PoV size benchmarks are very unprecise // - the worst case measured is usually very far off the actual value that is consumed on chain. // There's an ongoing item to improve it (mentioned on roundtable meeting). + + /// This benchmark isn't used directly in the runtime code, but it's convenient to do manual analysis of the benchmarked values. + /// Tier assignment is a PoV heavy operation, and it has to be properly analyzed, independently from other weight items. #[benchmark] fn dapp_tier_assignment(x: Linear<0, { max_number_of_contracts::() }>) { // Prepare init config (protocol state, tier params & config, etc.) initial_config::(); - let developer: T::AccountId = whitelisted_caller(); - for id in 0..x { - let smart_contract = T::BenchmarkHelper::get_smart_contract(id as u32); - assert_ok!(DappStaking::::register( - RawOrigin::Root.into(), - developer.clone().into(), - smart_contract, - )); - } - - // TODO: try to make this more "shuffled" so the generated vector ends up being more random - let mut amount = 1000 * MIN_TIER_THRESHOLD; - for id in 0..x { - let staker = account("staker", id.into(), 1337); - T::Currency::make_free_balance_be(&staker, amount); - assert_ok!(DappStaking::::lock( - RawOrigin::Signed(staker.clone()).into(), - amount, - )); - - let smart_contract = T::BenchmarkHelper::get_smart_contract(id as u32); - assert_ok!(DappStaking::::stake( - RawOrigin::Signed(staker.clone()).into(), - smart_contract, - amount, - )); - - // Slowly decrease the stake amount - amount.saturating_reduce(UNIT); - } - - // Advance to next era + // Register & stake contracts, to prepare for tier assignment. + prepare_contracts_for_tier_assignment::(x); advance_to_next_era::(); let reward_era = ActiveProtocolState::::get().era; diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs index 76214cca41..424f14006d 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/utils.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -27,7 +27,7 @@ use frame_system::Pallet as System; pub(super) fn run_to_block(n: BlockNumberFor) { while System::::block_number() < n { DappStaking::::on_finalize(System::::block_number()); - System::::set_block_number(System::::block_number() + One::one()); + System::::set_block_number(System::::block_number() + 1); // This is performed outside of dapps staking but we expect it before on_initialize DappStaking::::on_initialize(System::::block_number()); } @@ -114,7 +114,7 @@ pub(super) fn initial_config() { // Init protocol state ActiveProtocolState::::put(ProtocolState { era: 1, - next_era_start: era_length.saturating_mul(voting_period_length_in_eras.into()) + One::one(), + next_era_start: era_length.saturating_mul(voting_period_length_in_eras.into()) + 1, period_info: PeriodInfo { number: 1, subperiod: Subperiod::Voting, @@ -179,3 +179,37 @@ pub(super) fn initial_config() { pub(super) fn max_number_of_contracts() -> u32 { T::MaxNumberOfContracts::get().min(NUMBER_OF_SLOTS).into() } + +/// TODO +pub(super) fn prepare_contracts_for_tier_assignment(x: u32) { + let developer: T::AccountId = whitelisted_caller(); + for id in 0..x { + let smart_contract = T::BenchmarkHelper::get_smart_contract(id as u32); + assert_ok!(DappStaking::::register( + RawOrigin::Root.into(), + developer.clone().into(), + smart_contract, + )); + } + + // TODO: try to make this more "shuffled" so the generated vector ends up being more random + let mut amount = 1000 * MIN_TIER_THRESHOLD; + for id in 0..x { + let staker = account("staker", id.into(), 1337); + T::Currency::make_free_balance_be(&staker, amount); + assert_ok!(DappStaking::::lock( + RawOrigin::Signed(staker.clone()).into(), + amount, + )); + + let smart_contract = T::BenchmarkHelper::get_smart_contract(id as u32); + assert_ok!(DappStaking::::stake( + RawOrigin::Signed(staker.clone()).into(), + smart_contract, + amount, + )); + + // Slowly decrease the stake amount + amount.saturating_reduce(UNIT); + } +} diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index dd26da7a2b..be3579020d 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -52,7 +52,7 @@ use sp_runtime::{ }; pub use sp_std::vec::Vec; -use astar_primitives::Balance; +use astar_primitives::{Balance, BlockNumber}; pub use pallet::*; @@ -91,7 +91,7 @@ pub mod pallet { } #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent> @@ -121,7 +121,7 @@ pub mod pallet { /// Length of a standard era in block numbers. #[pallet::constant] - type StandardEraLength: Get; + type StandardEraLength: Get; /// Length of the `Voting` subperiod in standard eras. /// Although `Voting` subperiod only consumes one 'era', we still measure its length in standard eras @@ -355,8 +355,7 @@ pub mod pallet { /// General information about dApp staking protocol state. #[pallet::storage] #[pallet::whitelist_storage] - pub type ActiveProtocolState = - StorageValue<_, ProtocolState>, ValueQuery>; + pub type ActiveProtocolState = StorageValue<_, ProtocolState, ValueQuery>; /// Counter for unique dApp identifiers. #[pallet::storage] @@ -494,7 +493,9 @@ pub mod pallet { // Prepare initial protocol state let protocol_state = ProtocolState { era: 1, - next_era_start: Pallet::::blocks_per_voting_period() + 1_u32.into(), + next_era_start: Pallet::::blocks_per_voting_period() + .checked_add(1) + .expect("Must not overflow - especially not at genesis."), period_info: PeriodInfo { number: 1, subperiod: Subperiod::Voting, @@ -512,8 +513,8 @@ pub mod pallet { } #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(now: BlockNumberFor) -> Weight { + impl Hooks for Pallet { + fn on_initialize(now: BlockNumber) -> Weight { let mut protocol_state = ActiveProtocolState::::get(); // We should not modify pallet storage while in maintenance mode. @@ -1647,7 +1648,7 @@ pub mod pallet { } /// Returns the number of blocks per voting period. - pub(crate) fn blocks_per_voting_period() -> BlockNumberFor { + pub(crate) fn blocks_per_voting_period() -> BlockNumber { T::StandardEraLength::get() .saturating_mul(T::StandardErasPerVotingSubperiod::get().into()) } @@ -1670,7 +1671,7 @@ pub mod pallet { } /// Unlocking period expressed in the number of blocks. - pub(crate) fn unlock_period() -> BlockNumberFor { + pub(crate) fn unlock_period() -> BlockNumber { T::StandardEraLength::get().saturating_mul(T::UnlockingPeriod::get().into()) } diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 18c5bd293d..00e2732bdc 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -24,7 +24,7 @@ use crate::{ use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU128, ConstU32, ConstU64}, + traits::{ConstU128, ConstU32}, weights::Weight, }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -32,14 +32,14 @@ use sp_arithmetic::fixed_point::FixedU64; use sp_core::H256; use sp_io::TestExternalities; use sp_runtime::{ - testing::Header, + generic::Header, // TODO: create testing primitives & move it there? traits::{BlakeTwo256, IdentityLookup}, Permill, }; +use astar_primitives::{Balance, BlockNumber}; + pub(crate) type AccountId = u64; -pub(crate) type BlockNumber = u64; -pub(crate) type Balance = u128; pub(crate) const EXISTENTIAL_DEPOSIT: Balance = 2; pub(crate) const MINIMUM_LOCK_AMOUNT: Balance = 10; @@ -61,7 +61,7 @@ construct_runtime!( ); parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: BlockNumber = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0)); } @@ -78,7 +78,7 @@ impl frame_system::Config for Test { type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; - type Header = Header; + type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type DbWeight = (); @@ -157,7 +157,7 @@ impl pallet_dapp_staking::Config for Test { type ManagerOrigin = frame_system::EnsureRoot; type NativePriceProvider = DummyPriceProvider; type RewardPoolProvider = DummyRewardPoolProvider; - type StandardEraLength = ConstU64<10>; + type StandardEraLength = ConstU32<10>; type StandardErasPerVotingSubperiod = ConstU32<8>; type StandardErasPerBuildAndEarnSubperiod = ConstU32<16>; type EraRewardSpanLength = ConstU32<8>; @@ -278,7 +278,7 @@ impl ExtBuilder { /// Run to the specified block number. /// Function assumes first block has been initialized. -pub(crate) fn run_to_block(n: u64) { +pub(crate) fn run_to_block(n: BlockNumber) { while System::block_number() < n { DappStaking::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); @@ -292,7 +292,7 @@ pub(crate) fn run_to_block(n: u64) { /// Run for the specified number of blocks. /// Function assumes first block has been initialized. -pub(crate) fn run_for_blocks(n: u64) { +pub(crate) fn run_for_blocks(n: BlockNumber) { run_to_block(System::block_number() + n); } diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 14b3fa0bad..7b403ba3c4 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -19,8 +19,8 @@ use crate::test::mock::*; use crate::types::*; use crate::{ - pallet::Config, ActiveProtocolState, BlockNumberFor, ContractStake, CurrentEraInfo, DAppId, - DAppTiers, EraRewards, Event, IntegratedDApps, Ledger, NextDAppId, NextTierConfig, PeriodEnd, + pallet::Config, ActiveProtocolState, ContractStake, CurrentEraInfo, DAppId, DAppTiers, + EraRewards, Event, IntegratedDApps, Ledger, NextDAppId, NextTierConfig, PeriodEnd, PeriodEndInfo, StakerInfo, TierConfig, }; @@ -28,11 +28,13 @@ use frame_support::{assert_ok, traits::Get}; use sp_runtime::{traits::Zero, Perbill}; use std::collections::HashMap; +use astar_primitives::{Balance, BlockNumber}; + /// Helper struct used to store the entire pallet state snapshot. /// Used when comparison of before/after states is required. #[derive(Debug)] pub(crate) struct MemorySnapshot { - active_protocol_state: ProtocolState>, + active_protocol_state: ProtocolState, next_dapp_id: DAppId, current_era_info: EraInfo, integrated_dapps: HashMap< diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 42ec37c09b..53f570546e 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -29,6 +29,8 @@ use frame_support::{ }; use sp_runtime::traits::Zero; +use astar_primitives::{Balance, BlockNumber}; + #[test] fn maintenace_mode_works() { ExtBuilder::build().execute_with(|| { diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 50074ec7a6..07a61d0595 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::Balance; use frame_support::assert_ok; use sp_arithmetic::fixed_point::FixedU64; use sp_runtime::Permill; @@ -85,7 +85,7 @@ fn period_info_basic_checks() { #[test] fn protocol_state_default() { - let protocol_state = ProtocolState::::default(); + let protocol_state = ProtocolState::default(); assert_eq!(protocol_state.era, 0); assert_eq!( @@ -96,7 +96,7 @@ fn protocol_state_default() { #[test] fn protocol_state_basic_checks() { - let mut protocol_state = ProtocolState::::default(); + let mut protocol_state = ProtocolState::default(); let period_number = 5; let subperiod_end_era = 11; let next_era_start = 31; @@ -173,7 +173,7 @@ fn dapp_info_basic_checks() { #[test] fn unlocking_chunk_basic_check() { // Sanity check - let unlocking_chunk = UnlockingChunk::::default(); + let unlocking_chunk = UnlockingChunk::default(); assert!(unlocking_chunk.amount.is_zero()); assert!(unlocking_chunk.unlock_block.is_zero()); } @@ -181,7 +181,7 @@ fn unlocking_chunk_basic_check() { #[test] fn account_ledger_default() { get_u32_type!(UnlockingDummy, 5); - let acc_ledger = AccountLedger::::default(); + let acc_ledger = AccountLedger::::default(); assert!(acc_ledger.is_empty()); assert!(acc_ledger.active_locked_amount().is_zero()); @@ -190,7 +190,7 @@ fn account_ledger_default() { #[test] fn account_ledger_add_lock_amount_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // First step, sanity checks assert!(acc_ledger.active_locked_amount().is_zero()); @@ -209,7 +209,7 @@ fn account_ledger_add_lock_amount_works() { #[test] fn account_ledger_subtract_lock_amount_basic_usage_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check scenario // Cannot reduce if there is nothing locked, should be a noop @@ -250,10 +250,10 @@ fn account_ledger_subtract_lock_amount_basic_usage_works() { #[test] fn account_ledger_add_unlocking_chunk_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Base sanity check - let default_unlocking_chunk = UnlockingChunk::::default(); + let default_unlocking_chunk = UnlockingChunk::default(); assert!(default_unlocking_chunk.amount.is_zero()); assert!(default_unlocking_chunk.unlock_block.is_zero()); @@ -318,7 +318,7 @@ fn account_ledger_add_unlocking_chunk_works() { #[test] fn account_ledger_staked_amount_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check assert!(acc_ledger.staked_amount(0).is_zero()); @@ -355,7 +355,7 @@ fn account_ledger_staked_amount_works() { #[test] fn account_ledger_staked_amount_for_type_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // 1st scenario - 'current' entry is set, 'future' is None let (voting_1, build_and_earn_1, period) = (31, 43, 2); @@ -416,7 +416,7 @@ fn account_ledger_staked_amount_for_type_works() { #[test] fn account_ledger_stakeable_amount_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check for empty ledger assert!(acc_ledger.stakeable_amount(1).is_zero()); @@ -458,7 +458,7 @@ fn account_ledger_stakeable_amount_works() { #[test] fn account_ledger_staked_era_period_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); let (era_1, period) = (10, 2); let stake_amount_1 = StakeAmount { @@ -504,7 +504,7 @@ fn account_ledger_staked_era_period_works() { #[test] fn account_ledger_add_stake_amount_basic_example_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check let period_number = 2; @@ -584,7 +584,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { #[test] fn account_ledger_add_stake_amount_advanced_example_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // 1st scenario - stake some amount, and ensure values are as expected. let era_1 = 1; @@ -636,7 +636,7 @@ fn account_ledger_add_stake_amount_advanced_example_works() { #[test] fn account_ledger_add_stake_amount_invalid_era_or_period_fails() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Prep actions let era_1 = 5; @@ -703,7 +703,7 @@ fn account_ledger_add_stake_amount_invalid_era_or_period_fails() { #[test] fn account_ledger_add_stake_amount_too_large_amount_fails() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check assert_eq!( @@ -747,7 +747,7 @@ fn account_ledger_add_stake_amount_too_large_amount_fails() { #[test] fn account_ledger_unstake_amount_basic_scenario_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Prep actions let amount_1 = 19; @@ -803,7 +803,7 @@ fn account_ledger_unstake_amount_basic_scenario_works() { #[test] fn account_ledger_unstake_amount_advanced_scenario_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Prep actions let amount_1 = 19; @@ -885,7 +885,7 @@ fn account_ledger_unstake_amount_advanced_scenario_works() { #[test] fn account_ledger_unstake_from_invalid_era_fails() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Prep actions let amount_1 = 13; @@ -957,7 +957,7 @@ fn account_ledger_unstake_from_invalid_era_fails() { #[test] fn account_ledger_unstake_too_much_fails() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Prep actions let amount_1 = 23; @@ -982,7 +982,7 @@ fn account_ledger_unstake_too_much_fails() { #[test] fn account_ledger_unlockable_amount_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check scenario assert!(acc_ledger.unlockable_amount(0).is_zero()); @@ -1023,7 +1023,7 @@ fn account_ledger_unlockable_amount_works() { #[test] fn account_ledger_claim_unlocked_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check scenario assert!(acc_ledger.claim_unlocked(0).is_zero()); @@ -1057,7 +1057,7 @@ fn account_ledger_claim_unlocked_works() { #[test] fn account_ledger_consume_unlocking_chunks_works() { get_u32_type!(UnlockingDummy, 5); - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); // Sanity check scenario assert!(acc_ledger.consume_unlocking_chunks().is_zero()); @@ -1076,7 +1076,7 @@ fn account_ledger_expired_cleanup_works() { get_u32_type!(UnlockingDummy, 5); // 1st scenario - nothing is expired - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 3, build_and_earn: 7, @@ -1116,7 +1116,7 @@ fn account_ledger_claim_up_to_era_only_staked_without_cleanup_works() { let stake_era = 100; let acc_ledger_snapshot = { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 3, build_and_earn: 7, @@ -1189,7 +1189,7 @@ fn account_ledger_claim_up_to_era_only_staked_with_cleanup_works() { let stake_era = 100; let acc_ledger_snapshot = { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 3, build_and_earn: 7, @@ -1284,7 +1284,7 @@ fn account_ledger_claim_up_to_era_only_staked_future_without_cleanup_works() { let stake_era = 50; let acc_ledger_snapshot = { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked_future = Some(StakeAmount { voting: 5, build_and_earn: 11, @@ -1363,7 +1363,7 @@ fn account_ledger_claim_up_to_era_only_staked_future_with_cleanup_works() { let stake_era = 50; let acc_ledger_snapshot = { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked_future = Some(StakeAmount { voting: 2, build_and_earn: 17, @@ -1468,7 +1468,7 @@ fn account_ledger_claim_up_to_era_staked_and_staked_future_works() { let stake_era_2 = stake_era_1 + 1; let acc_ledger_snapshot = { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 3, build_and_earn: 7, @@ -1561,7 +1561,7 @@ fn account_ledger_claim_up_to_era_fails_for_historic_eras() { // Only staked entry { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 2, build_and_earn: 17, @@ -1576,7 +1576,7 @@ fn account_ledger_claim_up_to_era_fails_for_historic_eras() { // Only staked-future entry { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked_future = Some(StakeAmount { voting: 2, build_and_earn: 17, @@ -1591,7 +1591,7 @@ fn account_ledger_claim_up_to_era_fails_for_historic_eras() { // Both staked and staked-future entries { - let mut acc_ledger = AccountLedger::::default(); + let mut acc_ledger = AccountLedger::::default(); acc_ledger.staked = StakeAmount { voting: 2, build_and_earn: 17, diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index b629a82774..5f53ad666b 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -65,21 +65,20 @@ //! use frame_support::{pallet_prelude::*, BoundedVec}; -use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use sp_arithmetic::fixed_point::FixedU64; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, CheckedAdd, UniqueSaturatedInto, Zero}, + traits::{CheckedAdd, UniqueSaturatedInto, Zero}, FixedPointNumber, Permill, Saturating, }; pub use sp_std::{fmt::Debug, vec::Vec}; -use astar_primitives::Balance; +use astar_primitives::{Balance, BlockNumber}; use crate::pallet::Config; // Convenience type for `AccountLedger` usage. -pub type AccountLedgerFor = AccountLedger, ::MaxUnlockingChunks>; +pub type AccountLedgerFor = AccountLedger<::MaxUnlockingChunks>; // Convenience type for `DAppTierRewards` usage. pub type DAppTierRewardsFor = @@ -180,7 +179,7 @@ pub enum ForcingType { /// General information & state of the dApp staking protocol. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] -pub struct ProtocolState { +pub struct ProtocolState { /// Ongoing era number. #[codec(compact)] pub era: EraNumber, @@ -193,14 +192,11 @@ pub struct ProtocolState { pub maintenance: bool, } -impl Default for ProtocolState -where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen, -{ +impl Default for ProtocolState { fn default() -> Self { Self { era: 0, - next_era_start: BlockNumber::from(1_u32), + next_era_start: 1, period_info: PeriodInfo { number: 0, subperiod: Subperiod::Voting, @@ -211,10 +207,7 @@ where } } -impl ProtocolState -where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen, -{ +impl ProtocolState { /// Current subperiod. pub fn subperiod(&self) -> Subperiod { self.period_info.subperiod @@ -299,7 +292,7 @@ impl DAppInfo { /// How much was unlocked in some block. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] -pub struct UnlockingChunk { +pub struct UnlockingChunk { /// Amount undergoing the unlocking period. #[codec(compact)] pub amount: Balance, @@ -308,10 +301,7 @@ pub struct UnlockingChunk Default for UnlockingChunk -where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy, -{ +impl Default for UnlockingChunk { fn default() -> Self { Self { amount: Balance::zero(), @@ -332,15 +322,12 @@ where TypeInfo, )] #[scale_info(skip_type_params(UnlockingLen))] -pub struct AccountLedger< - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, - UnlockingLen: Get, -> { +pub struct AccountLedger> { /// How much active locked amount an account has. This can be used for staking. #[codec(compact)] pub locked: Balance, /// Vector of all the unlocking chunks. This is also considered _locked_ but cannot be used for staking. - pub unlocking: BoundedVec, UnlockingLen>, + pub unlocking: BoundedVec, /// Primary field used to store how much was staked in a particular era. pub staked: StakeAmount, /// Secondary field used to store 'stake' information for the 'next era'. @@ -354,9 +341,8 @@ pub struct AccountLedger< pub contract_stake_count: u32, } -impl Default for AccountLedger +impl Default for AccountLedger where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, UnlockingLen: Get, { fn default() -> Self { @@ -370,9 +356,8 @@ where } } -impl AccountLedger +impl AccountLedger where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, UnlockingLen: Get, { /// Empty if no locked/unlocking/staked info exists. From d063ddf61eef539e8b35be732f8812ea15b2ddf2 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 13:53:57 +0100 Subject: [PATCH 07/30] Extract on_init logic --- .../dapp-staking-v3/src/benchmarking/mod.rs | 54 +++- pallets/dapp-staking-v3/src/lib.rs | 300 ++++++++++-------- 2 files changed, 212 insertions(+), 142 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index d4d1aaa8ed..c3bbbdbd91 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -797,7 +797,7 @@ mod benchmarks { #[block] { - DappStaking::::on_initialize(state.next_era_start); + DappStaking::::era_and_period_handler(state.next_era_start, TierAssignment::Dummy); } assert_eq!( @@ -806,6 +806,58 @@ mod benchmarks { ); } + #[benchmark] + fn on_initialize_build_and_earn_to_voting() { + initial_config::(); + + // Get started + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::Voting, + "Sanity check." + ); + + // Advance to build&earn subperiod + advance_to_next_subperiod::(); + let snapshot_state = ActiveProtocolState::::get(); + + // Advance over to the last era of the subperiod, and then again to the last block of that era. + advance_to_era::( + ActiveProtocolState::::get() + .period_info + .subperiod_end_era - 1, + ); + run_to_block::(ActiveProtocolState::::get().next_era_start - 1); + + // Some sanity checks, we should still be in the build&earn subperiod, and in the first period. + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn + ); + assert_eq!( + ActiveProtocolState::::get().period_number(), + snapshot_state.period_number(), + ); + + let new_era_start_block = ActiveProtocolState::::get().next_era_start; + DappStaking::::on_finalize(new_era_start_block - 1); + System::::set_block_number(new_era_start_block); + + #[block] + { + DappStaking::::era_and_period_handler(new_era_start_block, TierAssignment::Dummy); + } + + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::Voting + ); + assert_eq!( + ActiveProtocolState::::get().period_number(), + snapshot_state.period_number() + 1, + ); + } + // TODO: investigate why the PoV size is so large here, even after removing read of `IntegratedDApps` storage. // Relevant file: polkadot-sdk/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs // UPDATE: after some investigation, it seems that PoV size benchmarks are very unprecise diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index be3579020d..3193a17750 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -74,6 +74,12 @@ const STAKING_ID: LockIdentifier = *b"dapstake"; const LOG_TARGET: &str = "dapp-staking"; +/// TODO +pub(crate) enum TierAssignment { + Real, + Dummy, +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -515,147 +521,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks for Pallet { fn on_initialize(now: BlockNumber) -> Weight { - let mut protocol_state = ActiveProtocolState::::get(); - - // We should not modify pallet storage while in maintenance mode. - // This is a safety measure, since maintenance mode is expected to be - // enabled in case some misbehavior or corrupted storage is detected. - if protocol_state.maintenance { - return T::DbWeight::get().reads(1); - } - - // Nothing to do if it's not new era - if !protocol_state.is_new_era(now) { - return T::DbWeight::get().reads(1); - } - - // At this point it's clear that an era change will happen - let mut era_info = CurrentEraInfo::::get(); - - let current_era = protocol_state.era; - let next_era = current_era.saturating_add(1); - let (maybe_period_event, era_reward) = match protocol_state.subperiod() { - // Voting subperiod only lasts for one 'prolonged' era - Subperiod::Voting => { - // For the sake of consistency, we put zero reward into storage. There are no rewards for the voting subperiod. - let era_reward = EraReward { - staker_reward_pool: Balance::zero(), - staked: era_info.total_staked_amount(), - dapp_reward_pool: Balance::zero(), - }; - - let subperiod_end_era = - next_era.saturating_add(T::StandardErasPerBuildAndEarnSubperiod::get()); - let build_and_earn_start_block = - now.saturating_add(T::StandardEraLength::get()); - protocol_state - .advance_to_next_subperiod(subperiod_end_era, build_and_earn_start_block); - - era_info.migrate_to_next_era(Some(protocol_state.subperiod())); - - // Update tier configuration to be used when calculating rewards for the upcoming eras - let next_tier_config = NextTierConfig::::take(); - TierConfig::::put(next_tier_config); - - ( - Some(Event::::NewSubperiod { - subperiod: protocol_state.subperiod(), - number: protocol_state.period_number(), - }), - era_reward, - ) - } - Subperiod::BuildAndEarn => { - let (staker_reward_pool, dapp_reward_pool) = - T::RewardPoolProvider::normal_reward_pools(); - let era_reward = EraReward { - staker_reward_pool, - staked: era_info.total_staked_amount(), - dapp_reward_pool, - }; - - // Distribute dapps into tiers, write it into storage - let dapp_tier_rewards = Self::get_dapp_tier_assignment( - current_era, - protocol_state.period_number(), - dapp_reward_pool, - ); - DAppTiers::::insert(¤t_era, dapp_tier_rewards); - - // Switch to `Voting` period if conditions are met. - if protocol_state.period_info.is_next_period(next_era) { - // Store info about period end - let bonus_reward_pool = T::RewardPoolProvider::bonus_reward_pool(); - PeriodEnd::::insert( - &protocol_state.period_number(), - PeriodEndInfo { - bonus_reward_pool, - total_vp_stake: era_info.staked_amount(Subperiod::Voting), - final_era: current_era, - }, - ); - - // For the sake of consistency we treat the whole `Voting` period as a single era. - // This means no special handling is required for this period, it only lasts potentially longer than a single standard era. - let subperiod_end_era = next_era.saturating_add(1); - let voting_period_length = Self::blocks_per_voting_period(); - let next_era_start_block = now.saturating_add(voting_period_length); - - protocol_state - .advance_to_next_subperiod(subperiod_end_era, next_era_start_block); - - era_info.migrate_to_next_era(Some(protocol_state.subperiod())); - - // Re-calculate tier configuration for the upcoming new period - let tier_params = StaticTierParams::::get(); - let average_price = T::NativePriceProvider::average_price(); - let new_tier_config = - TierConfig::::get().calculate_new(average_price, &tier_params); - NextTierConfig::::put(new_tier_config); - - ( - Some(Event::::NewSubperiod { - subperiod: protocol_state.subperiod(), - number: protocol_state.period_number(), - }), - era_reward, - ) - } else { - let next_era_start_block = now.saturating_add(T::StandardEraLength::get()); - protocol_state.next_era_start = next_era_start_block; - - era_info.migrate_to_next_era(None); - - (None, era_reward) - } - } - }; - - // Update storage items - protocol_state.era = next_era; - ActiveProtocolState::::put(protocol_state); - - CurrentEraInfo::::put(era_info); - - let era_span_index = Self::era_reward_span_index(current_era); - let mut span = EraRewards::::get(&era_span_index).unwrap_or(EraRewardSpan::new()); - if let Err(_) = span.push(current_era, era_reward) { - // This must never happen but we log the error just in case. - log::error!( - target: LOG_TARGET, - "Failed to push era {} into the era reward span.", - current_era - ); - } - EraRewards::::insert(&era_span_index, span); - - Self::deposit_event(Event::::NewEra { era: next_era }); - if let Some(period_event) = maybe_period_event { - Self::deposit_event(period_event); - } - - // TODO: benchmark later - T::DbWeight::get().reads_writes(3, 3) + Self::era_and_period_handler(now, TierAssignment::Real) } } @@ -1794,5 +1660,157 @@ pub mod pallet { ) .unwrap_or_default() } + + /// TODO + pub(crate) fn era_and_period_handler( + now: BlockNumber, + tier_assignment: TierAssignment, + ) -> Weight { + let mut protocol_state = ActiveProtocolState::::get(); + + // We should not modify pallet storage while in maintenance mode. + // This is a safety measure, since maintenance mode is expected to be + // enabled in case some misbehavior or corrupted storage is detected. + if protocol_state.maintenance { + return T::DbWeight::get().reads(1); + } + + // Nothing to do if it's not new era + if !protocol_state.is_new_era(now) { + return T::DbWeight::get().reads(1); + } + + // At this point it's clear that an era change will happen + let mut era_info = CurrentEraInfo::::get(); + + let current_era = protocol_state.era; + let next_era = current_era.saturating_add(1); + let (maybe_period_event, era_reward) = match protocol_state.subperiod() { + // Voting subperiod only lasts for one 'prolonged' era + Subperiod::Voting => { + // For the sake of consistency, we put zero reward into storage. There are no rewards for the voting subperiod. + let era_reward = EraReward { + staker_reward_pool: Balance::zero(), + staked: era_info.total_staked_amount(), + dapp_reward_pool: Balance::zero(), + }; + + let subperiod_end_era = + next_era.saturating_add(T::StandardErasPerBuildAndEarnSubperiod::get()); + let build_and_earn_start_block = + now.saturating_add(T::StandardEraLength::get()); + protocol_state + .advance_to_next_subperiod(subperiod_end_era, build_and_earn_start_block); + + era_info.migrate_to_next_era(Some(protocol_state.subperiod())); + + // Update tier configuration to be used when calculating rewards for the upcoming eras + let next_tier_config = NextTierConfig::::take(); + TierConfig::::put(next_tier_config); + + ( + Some(Event::::NewSubperiod { + subperiod: protocol_state.subperiod(), + number: protocol_state.period_number(), + }), + era_reward, + ) + } + Subperiod::BuildAndEarn => { + let (staker_reward_pool, dapp_reward_pool) = + T::RewardPoolProvider::normal_reward_pools(); + let era_reward = EraReward { + staker_reward_pool, + staked: era_info.total_staked_amount(), + dapp_reward_pool, + }; + + // TODO: docs! + // Distribute dapps into tiers, write it into storage + let dapp_tier_rewards = match tier_assignment { + TierAssignment::Real => Self::get_dapp_tier_assignment( + current_era, + protocol_state.period_number(), + dapp_reward_pool, + ), + TierAssignment::Dummy => DAppTierRewardsFor::::default(), + }; + DAppTiers::::insert(¤t_era, dapp_tier_rewards); + + // Switch to `Voting` period if conditions are met. + if protocol_state.period_info.is_next_period(next_era) { + // Store info about period end + let bonus_reward_pool = T::RewardPoolProvider::bonus_reward_pool(); + PeriodEnd::::insert( + &protocol_state.period_number(), + PeriodEndInfo { + bonus_reward_pool, + total_vp_stake: era_info.staked_amount(Subperiod::Voting), + final_era: current_era, + }, + ); + + // For the sake of consistency we treat the whole `Voting` period as a single era. + // This means no special handling is required for this period, it only lasts potentially longer than a single standard era. + let subperiod_end_era = next_era.saturating_add(1); + let voting_period_length = Self::blocks_per_voting_period(); + let next_era_start_block = now.saturating_add(voting_period_length); + + protocol_state + .advance_to_next_subperiod(subperiod_end_era, next_era_start_block); + + era_info.migrate_to_next_era(Some(protocol_state.subperiod())); + + // Re-calculate tier configuration for the upcoming new period + let tier_params = StaticTierParams::::get(); + let average_price = T::NativePriceProvider::average_price(); + let new_tier_config = + TierConfig::::get().calculate_new(average_price, &tier_params); + NextTierConfig::::put(new_tier_config); + + ( + Some(Event::::NewSubperiod { + subperiod: protocol_state.subperiod(), + number: protocol_state.period_number(), + }), + era_reward, + ) + } else { + let next_era_start_block = now.saturating_add(T::StandardEraLength::get()); + protocol_state.next_era_start = next_era_start_block; + + era_info.migrate_to_next_era(None); + + (None, era_reward) + } + } + }; + + // Update storage items + protocol_state.era = next_era; + ActiveProtocolState::::put(protocol_state); + + CurrentEraInfo::::put(era_info); + + let era_span_index = Self::era_reward_span_index(current_era); + let mut span = EraRewards::::get(&era_span_index).unwrap_or(EraRewardSpan::new()); + if let Err(_) = span.push(current_era, era_reward) { + // This must never happen but we log the error just in case. + log::error!( + target: LOG_TARGET, + "Failed to push era {} into the era reward span.", + current_era + ); + } + EraRewards::::insert(&era_span_index, span); + + Self::deposit_event(Event::::NewEra { era: next_era }); + if let Some(period_event) = maybe_period_event { + Self::deposit_event(period_event); + } + + // TODO: benchmark later + T::DbWeight::get().reads_writes(3, 3) + } } } From 1785d9560f0c6f70568bba3a6405a5ad5c3f2e6a Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 13:59:13 +0100 Subject: [PATCH 08/30] Some renaming --- .../dapp-staking-v3/src/benchmarking/mod.rs | 3 +- .../dapp-staking-v3/src/benchmarking/utils.rs | 2 +- pallets/dapp-staking-v3/src/lib.rs | 20 +++-- pallets/dapp-staking-v3/src/test/mock.rs | 2 +- .../dapp-staking-v3/src/test/testing_utils.rs | 6 +- pallets/dapp-staking-v3/src/test/tests.rs | 20 ++--- .../dapp-staking-v3/src/test/tests_types.rs | 90 ++++++++++--------- pallets/dapp-staking-v3/src/types.rs | 16 ++-- 8 files changed, 85 insertions(+), 74 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index c3bbbdbd91..c5c54614f9 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -825,7 +825,8 @@ mod benchmarks { advance_to_era::( ActiveProtocolState::::get() .period_info - .subperiod_end_era - 1, + .next_subperiod_start_era + - 1, ); run_to_block::(ActiveProtocolState::::get().next_era_start - 1); diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs index 424f14006d..f99885c83d 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/utils.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -118,7 +118,7 @@ pub(super) fn initial_config() { period_info: PeriodInfo { number: 1, subperiod: Subperiod::Voting, - subperiod_end_era: 2, + next_subperiod_start_era: 2, }, maintenance: false, }); diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 3193a17750..e50ef2e249 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -505,7 +505,7 @@ pub mod pallet { period_info: PeriodInfo { number: 1, subperiod: Subperiod::Voting, - subperiod_end_era: 2, + next_subperiod_start_era: 2, }, maintenance: false, }; @@ -1461,7 +1461,7 @@ pub mod pallet { match forcing_type { ForcingType::Era => (), ForcingType::Subperiod => { - state.period_info.subperiod_end_era = state.era.saturating_add(1); + state.period_info.next_subperiod_start_era = state.era.saturating_add(1); } } }); @@ -1695,12 +1695,14 @@ pub mod pallet { dapp_reward_pool: Balance::zero(), }; - let subperiod_end_era = + let next_subperiod_start_era = next_era.saturating_add(T::StandardErasPerBuildAndEarnSubperiod::get()); let build_and_earn_start_block = now.saturating_add(T::StandardEraLength::get()); - protocol_state - .advance_to_next_subperiod(subperiod_end_era, build_and_earn_start_block); + protocol_state.advance_to_next_subperiod( + next_subperiod_start_era, + build_and_earn_start_block, + ); era_info.migrate_to_next_era(Some(protocol_state.subperiod())); @@ -1752,12 +1754,14 @@ pub mod pallet { // For the sake of consistency we treat the whole `Voting` period as a single era. // This means no special handling is required for this period, it only lasts potentially longer than a single standard era. - let subperiod_end_era = next_era.saturating_add(1); + let next_subperiod_start_era = next_era.saturating_add(1); let voting_period_length = Self::blocks_per_voting_period(); let next_era_start_block = now.saturating_add(voting_period_length); - protocol_state - .advance_to_next_subperiod(subperiod_end_era, next_era_start_block); + protocol_state.advance_to_next_subperiod( + next_subperiod_start_era, + next_era_start_block, + ); era_info.migrate_to_next_era(Some(protocol_state.subperiod())); diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 00e2732bdc..2847e126dd 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -209,7 +209,7 @@ impl ExtBuilder { period_info: PeriodInfo { number: 1, subperiod: Subperiod::Voting, - subperiod_end_era: 2, + next_subperiod_start_era: 2, }, maintenance: false, }); diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 7b403ba3c4..2923ab0586 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -1135,7 +1135,7 @@ pub(crate) fn assert_block_bump(pre_snapshot: &MemorySnapshot) { let is_new_subperiod = pre_snapshot .active_protocol_state .period_info - .subperiod_end_era + .next_subperiod_start_era <= post_snapshot.active_protocol_state.era; // 1. Verify protocol state @@ -1154,7 +1154,7 @@ pub(crate) fn assert_block_bump(pre_snapshot: &MemorySnapshot) { let eras_per_bep: EraNumber = ::StandardErasPerBuildAndEarnSubperiod::get(); assert_eq!( - post_protoc_state.period_info.subperiod_end_era, + post_protoc_state.period_info.next_subperiod_start_era, post_protoc_state.era + eras_per_bep, "Build&earn must last for the predefined amount of standard eras." ); @@ -1179,7 +1179,7 @@ pub(crate) fn assert_block_bump(pre_snapshot: &MemorySnapshot) { "Ending 'Build&Earn' triggers a new period." ); assert_eq!( - post_protoc_state.period_info.subperiod_end_era, + post_protoc_state.period_info.next_subperiod_start_era, post_protoc_state.era + 1, "Voting era must last for a single era." ); diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 53f570546e..e2de5de36f 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -913,7 +913,7 @@ fn stake_in_final_era_fails() { // Force Build&Earn period ActiveProtocolState::::mutate(|state| { state.period_info.subperiod = Subperiod::BuildAndEarn; - state.period_info.subperiod_end_era = state.era + 1; + state.period_info.next_subperiod_start_era = state.era + 1; }); // Try to stake in the final era of the period, which should fail. @@ -1376,7 +1376,7 @@ fn claim_staker_rewards_after_expiry_fails() { advance_to_era( ActiveProtocolState::::get() .period_info - .subperiod_end_era + .next_subperiod_start_era - 1, ); assert_claim_staker_rewards(account); @@ -1887,8 +1887,8 @@ fn force_era_works() { System::block_number() + 1, ); assert_eq!( - ActiveProtocolState::::get().period_end_era(), - init_state.period_end_era(), + ActiveProtocolState::::get().next_subperiod_start_era(), + init_state.next_subperiod_start_era(), ); // Go to the next block, and ensure new era is started @@ -1909,7 +1909,7 @@ fn force_era_works() { init_state.next_era_start > System::block_number() + 1, "Sanity check, new era cannot start in next block, otherwise the test doesn't guarantee it tests what's expected." ); - assert!(init_state.period_end_era() > init_state.era + 1, "Sanity check, otherwise the test doesn't guarantee it tests what's expected."); + assert!(init_state.next_subperiod_start_era() > init_state.era + 1, "Sanity check, otherwise the test doesn't guarantee it tests what's expected."); assert_ok!(DappStaking::force(RuntimeOrigin::root(), ForcingType::Era)); System::assert_last_event(RuntimeEvent::DappStaking(Event::Force { forcing_type: ForcingType::Era, @@ -1921,8 +1921,8 @@ fn force_era_works() { System::block_number() + 1, ); assert_eq!( - ActiveProtocolState::::get().period_end_era(), - init_state.period_end_era(), + ActiveProtocolState::::get().next_subperiod_start_era(), + init_state.next_subperiod_start_era(), "Only era is bumped, but we don't expect to switch over to the next subperiod." ); @@ -1965,7 +1965,7 @@ fn force_subperiod_works() { System::block_number() + 1, ); assert_eq!( - ActiveProtocolState::::get().period_end_era(), + ActiveProtocolState::::get().next_subperiod_start_era(), init_state.era + 1, "The switch to the next subperiod must happen in the next era." ); @@ -1990,7 +1990,7 @@ fn force_subperiod_works() { init_state.next_era_start > System::block_number() + 1, "Sanity check, new era cannot start in next block, otherwise the test doesn't guarantee it tests what's expected." ); - assert!(init_state.period_end_era() > init_state.era + 1, "Sanity check, otherwise the test doesn't guarantee it tests what's expected."); + assert!(init_state.next_subperiod_start_era() > init_state.era + 1, "Sanity check, otherwise the test doesn't guarantee it tests what's expected."); assert_ok!(DappStaking::force(RuntimeOrigin::root(), ForcingType::Subperiod)); System::assert_last_event(RuntimeEvent::DappStaking(Event::Force { forcing_type: ForcingType::Subperiod, @@ -2002,7 +2002,7 @@ fn force_subperiod_works() { System::block_number() + 1, ); assert_eq!( - ActiveProtocolState::::get().period_end_era(), + ActiveProtocolState::::get().next_subperiod_start_era(), init_state.era + 1, "The switch to the next subperiod must happen in the next era." ); diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 07a61d0595..054c69a6be 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -45,26 +45,26 @@ fn subperiod_sanity_check() { #[test] fn period_info_basic_checks() { let period_number = 2; - let subperiod_end_era = 5; + let next_subperiod_start_era = 5; let info = PeriodInfo { number: period_number, subperiod: Subperiod::Voting, - subperiod_end_era: subperiod_end_era, + next_subperiod_start_era: next_subperiod_start_era, }; // Sanity checks assert_eq!(info.number, period_number); assert_eq!(info.subperiod, Subperiod::Voting); - assert_eq!(info.subperiod_end_era, subperiod_end_era); + assert_eq!(info.next_subperiod_start_era, next_subperiod_start_era); // Voting period checks - assert!(!info.is_next_period(subperiod_end_era - 1)); - assert!(!info.is_next_period(subperiod_end_era)); - assert!(!info.is_next_period(subperiod_end_era + 1)); + assert!(!info.is_next_period(next_subperiod_start_era - 1)); + assert!(!info.is_next_period(next_subperiod_start_era)); + assert!(!info.is_next_period(next_subperiod_start_era + 1)); for era in vec![ - subperiod_end_era - 1, - subperiod_end_era, - subperiod_end_era + 1, + next_subperiod_start_era - 1, + next_subperiod_start_era, + next_subperiod_start_era + 1, ] { assert!( !info.is_next_period(era), @@ -76,11 +76,11 @@ fn period_info_basic_checks() { let info = PeriodInfo { number: period_number, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: subperiod_end_era, + next_subperiod_start_era: next_subperiod_start_era, }; - assert!(!info.is_next_period(subperiod_end_era - 1)); - assert!(info.is_next_period(subperiod_end_era)); - assert!(info.is_next_period(subperiod_end_era + 1)); + assert!(!info.is_next_period(next_subperiod_start_era - 1)); + assert!(info.is_next_period(next_subperiod_start_era)); + assert!(info.is_next_period(next_subperiod_start_era + 1)); } #[test] @@ -98,12 +98,12 @@ fn protocol_state_default() { fn protocol_state_basic_checks() { let mut protocol_state = ProtocolState::default(); let period_number = 5; - let subperiod_end_era = 11; + let next_subperiod_start_era = 11; let next_era_start = 31; protocol_state.period_info = PeriodInfo { number: period_number, subperiod: Subperiod::Voting, - subperiod_end_era: subperiod_end_era, + next_subperiod_start_era: next_subperiod_start_era, }; protocol_state.next_era_start = next_era_start; @@ -116,30 +116,36 @@ fn protocol_state_basic_checks() { assert!(protocol_state.is_new_era(next_era_start + 1)); // Toggle new period type check - 'Voting' to 'BuildAndEarn' - let subperiod_end_era_1 = 23; + let next_subperiod_start_era_1 = 23; let next_era_start_1 = 41; - protocol_state.advance_to_next_subperiod(subperiod_end_era_1, next_era_start_1); + protocol_state.advance_to_next_subperiod(next_subperiod_start_era_1, next_era_start_1); assert_eq!(protocol_state.subperiod(), Subperiod::BuildAndEarn); assert_eq!( protocol_state.period_number(), period_number, "Switching from 'Voting' to 'BuildAndEarn' should not trigger period bump." ); - assert_eq!(protocol_state.period_end_era(), subperiod_end_era_1); + assert_eq!( + protocol_state.next_subperiod_start_era(), + next_subperiod_start_era_1 + ); assert!(!protocol_state.is_new_era(next_era_start_1 - 1)); assert!(protocol_state.is_new_era(next_era_start_1)); // Toggle from 'BuildAndEarn' over to 'Voting' - let subperiod_end_era_2 = 24; + let next_subperiod_start_era_2 = 24; let next_era_start_2 = 91; - protocol_state.advance_to_next_subperiod(subperiod_end_era_2, next_era_start_2); + protocol_state.advance_to_next_subperiod(next_subperiod_start_era_2, next_era_start_2); assert_eq!(protocol_state.subperiod(), Subperiod::Voting); assert_eq!( protocol_state.period_number(), period_number + 1, "Switching from 'BuildAndEarn' to 'Voting' must trigger period bump." ); - assert_eq!(protocol_state.period_end_era(), subperiod_end_era_2); + assert_eq!( + protocol_state.next_subperiod_start_era(), + next_subperiod_start_era_2 + ); assert!(protocol_state.is_new_era(next_era_start_2)); } @@ -515,7 +521,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { PeriodInfo { number: period_number, subperiod: Subperiod::Voting, - subperiod_end_era: 0 + next_subperiod_start_era: 0 } ) .is_ok()); @@ -528,7 +534,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::Voting, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; let lock_amount = 17; let stake_amount = 11; @@ -565,7 +571,7 @@ fn account_ledger_add_stake_amount_basic_example_works() { let period_info_2 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; let era_2 = era_1 + 1; assert!(acc_ledger.add_stake_amount(1, era_2, period_info_2).is_ok()); @@ -592,7 +598,7 @@ fn account_ledger_add_stake_amount_advanced_example_works() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::Voting, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; let lock_amount = 17; let stake_amount_1 = 11; @@ -644,7 +650,7 @@ fn account_ledger_add_stake_amount_invalid_era_or_period_fails() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::Voting, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; let lock_amount = 13; let stake_amount = 7; @@ -667,7 +673,7 @@ fn account_ledger_add_stake_amount_invalid_era_or_period_fails() { PeriodInfo { number: period_1 + 1, subperiod: Subperiod::Voting, - subperiod_end_era: 100 + next_subperiod_start_era: 100 } ), Err(AccountLedgerError::InvalidPeriod) @@ -693,7 +699,7 @@ fn account_ledger_add_stake_amount_invalid_era_or_period_fails() { PeriodInfo { number: period_1 + 1, subperiod: Subperiod::Voting, - subperiod_end_era: 100 + next_subperiod_start_era: 100 } ), Err(AccountLedgerError::InvalidPeriod) @@ -713,7 +719,7 @@ fn account_ledger_add_stake_amount_too_large_amount_fails() { PeriodInfo { number: 1, subperiod: Subperiod::Voting, - subperiod_end_era: 100 + next_subperiod_start_era: 100 } ), Err(AccountLedgerError::UnavailableStakeFunds) @@ -725,7 +731,7 @@ fn account_ledger_add_stake_amount_too_large_amount_fails() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::Voting, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; let lock_amount = 13; acc_ledger.add_lock_amount(lock_amount); @@ -756,7 +762,7 @@ fn account_ledger_unstake_amount_basic_scenario_works() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; acc_ledger.add_lock_amount(amount_1); @@ -812,7 +818,7 @@ fn account_ledger_unstake_amount_advanced_scenario_works() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; acc_ledger.add_lock_amount(amount_1); @@ -894,7 +900,7 @@ fn account_ledger_unstake_from_invalid_era_fails() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; acc_ledger.add_lock_amount(amount_1); assert!(acc_ledger @@ -921,7 +927,7 @@ fn account_ledger_unstake_from_invalid_era_fails() { PeriodInfo { number: period_1 + 1, subperiod: Subperiod::Voting, - subperiod_end_era: 100 + next_subperiod_start_era: 100 } ), Err(AccountLedgerError::InvalidPeriod) @@ -947,7 +953,7 @@ fn account_ledger_unstake_from_invalid_era_fails() { PeriodInfo { number: period_1 + 1, subperiod: Subperiod::Voting, - subperiod_end_era: 100 + next_subperiod_start_era: 100 } ), Err(AccountLedgerError::InvalidPeriod) @@ -966,7 +972,7 @@ fn account_ledger_unstake_too_much_fails() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; acc_ledger.add_lock_amount(amount_1); assert!(acc_ledger @@ -999,7 +1005,7 @@ fn account_ledger_unlockable_amount_works() { let period_info = PeriodInfo { number: stake_period, subperiod: Subperiod::Voting, - subperiod_end_era: 100, + next_subperiod_start_era: 100, }; assert!(acc_ledger .add_stake_amount(stake_amount, lock_era, period_info) @@ -2240,7 +2246,7 @@ fn contract_stake_amount_stake_is_ok() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::Voting, - subperiod_end_era: 20, + next_subperiod_start_era: 20, }; let amount_1 = 31; contract_stake.stake(amount_1, period_info_1, era_1); @@ -2268,7 +2274,7 @@ fn contract_stake_amount_stake_is_ok() { let period_info_1 = PeriodInfo { number: period_1, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 20, + next_subperiod_start_era: 20, }; contract_stake.stake(amount_1, period_info_1, era_1); let entry_1_2 = contract_stake.get(stake_era_1, period_1).unwrap(); @@ -2310,7 +2316,7 @@ fn contract_stake_amount_stake_is_ok() { let period_info_2 = PeriodInfo { number: period_2, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 20, + next_subperiod_start_era: 20, }; let amount_3 = 41; @@ -2365,7 +2371,7 @@ fn contract_stake_amount_unstake_is_ok() { let period_info = PeriodInfo { number: period, subperiod: Subperiod::Voting, - subperiod_end_era: 20, + next_subperiod_start_era: 20, }; let stake_amount = 100; contract_stake.stake(stake_amount, period_info, era_1); @@ -2388,7 +2394,7 @@ fn contract_stake_amount_unstake_is_ok() { let period_info = PeriodInfo { number: period, subperiod: Subperiod::BuildAndEarn, - subperiod_end_era: 40, + next_subperiod_start_era: 40, }; let era_2 = era_1 + 1; diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 5f53ad666b..0cd7cc7c18 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -141,16 +141,16 @@ pub struct PeriodInfo { pub number: PeriodNumber, /// Subperiod type. pub subperiod: Subperiod, - /// Last era of the subperiod, after this a new subperiod should start. + /// Era in which the new subperiod starts. #[codec(compact)] - pub subperiod_end_era: EraNumber, + pub next_subperiod_start_era: EraNumber, } impl PeriodInfo { /// `true` if the provided era belongs to the next period, `false` otherwise. /// It's only possible to provide this information correctly for the ongoing `BuildAndEarn` subperiod. pub fn is_next_period(&self, era: EraNumber) -> bool { - self.subperiod == Subperiod::BuildAndEarn && self.subperiod_end_era <= era + self.subperiod == Subperiod::BuildAndEarn && self.next_subperiod_start_era <= era } } @@ -200,7 +200,7 @@ impl Default for ProtocolState { period_info: PeriodInfo { number: 0, subperiod: Subperiod::Voting, - subperiod_end_era: 2, + next_subperiod_start_era: 2, }, maintenance: false, } @@ -219,8 +219,8 @@ impl ProtocolState { } /// Ending era of current period - pub fn period_end_era(&self) -> EraNumber { - self.period_info.subperiod_end_era + pub fn next_subperiod_start_era(&self) -> EraNumber { + self.period_info.next_subperiod_start_era } /// Checks whether a new era should be triggered, based on the provided _current_ block number argument @@ -232,7 +232,7 @@ impl ProtocolState { /// Triggers the next subperiod, updating appropriate parameters. pub fn advance_to_next_subperiod( &mut self, - subperiod_end_era: EraNumber, + next_subperiod_start_era: EraNumber, next_era_start: BlockNumber, ) { let period_number = if self.subperiod() == Subperiod::BuildAndEarn { @@ -244,7 +244,7 @@ impl ProtocolState { self.period_info = PeriodInfo { number: period_number, subperiod: self.subperiod().next(), - subperiod_end_era, + next_subperiod_start_era, }; self.next_era_start = next_era_start; } From 7a0ac619f367240bbe09afe06f109bf4612325cd Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 14:14:59 +0100 Subject: [PATCH 09/30] More benchmarks --- .../dapp-staking-v3/src/benchmarking/mod.rs | 85 +++++++++++-------- .../dapp-staking-v3/src/benchmarking/utils.rs | 5 +- pallets/dapp-staking-v3/src/lib.rs | 13 ++- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index c5c54614f9..899fb3efef 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -205,39 +205,6 @@ mod benchmarks { ); } - // TODO: maybe this is not needed. Compare it after running benchmarks to the 'not-full' unlock - #[benchmark] - fn full_unlock() { - initial_config::(); - - let staker: T::AccountId = whitelisted_caller(); - let owner: T::AccountId = account("dapp_owner", 0, SEED); - let smart_contract = T::BenchmarkHelper::get_smart_contract(1); - assert_ok!(DappStaking::::register( - RawOrigin::Root.into(), - owner.clone().into(), - smart_contract.clone(), - )); - - let amount = T::MinimumLockedAmount::get() * 2; - T::Currency::make_free_balance_be(&staker, amount); - assert_ok!(DappStaking::::lock( - RawOrigin::Signed(staker.clone()).into(), - amount, - )); - - #[extrinsic_call] - unlock(RawOrigin::Signed(staker.clone()), amount); - - assert_last_event::( - Event::::Unlocking { - account: staker, - amount, - } - .into(), - ); - } - #[benchmark] fn claim_unlocked(x: Linear<0, { T::MaxNumberOfStakedContracts::get() }>) { // Prepare staker account and lock some amount @@ -791,6 +758,9 @@ mod benchmarks { let state = ActiveProtocolState::::get(); assert_eq!(state.subperiod(), Subperiod::Voting, "Sanity check."); + // Register & stake contracts, just so we don't have empty stakes. + prepare_contracts_for_tier_assignment::(max_number_of_contracts::()); + run_to_block::(state.next_era_start - 1); DappStaking::::on_finalize(state.next_era_start - 1); System::::set_block_number(state.next_era_start); @@ -817,6 +787,9 @@ mod benchmarks { "Sanity check." ); + // Register & stake contracts, just so we don't have empty stakes. + prepare_contracts_for_tier_assignment::(max_number_of_contracts::()); + // Advance to build&earn subperiod advance_to_next_subperiod::(); let snapshot_state = ActiveProtocolState::::get(); @@ -859,12 +832,56 @@ mod benchmarks { ); } + #[benchmark] + fn on_initialize_build_and_earn_to_build_and_earn() { + initial_config::(); + + // Register & stake contracts, just so we don't have empty stakes. + prepare_contracts_for_tier_assignment::(max_number_of_contracts::()); + + // Advance to build&earn subperiod + advance_to_next_subperiod::(); + let snapshot_state = ActiveProtocolState::::get(); + + // Advance over to the next era, and then again to the last block of that era. + advance_to_next_era::(); + run_to_block::(ActiveProtocolState::::get().next_era_start - 1); + + // Some sanity checks, we should still be in the build&earn subperiod, and in the first period. + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn + ); + assert_eq!( + ActiveProtocolState::::get().period_number(), + snapshot_state.period_number(), + ); + + let new_era_start_block = ActiveProtocolState::::get().next_era_start; + DappStaking::::on_finalize(new_era_start_block - 1); + System::::set_block_number(new_era_start_block); + + #[block] + { + DappStaking::::era_and_period_handler(new_era_start_block, TierAssignment::Dummy); + } + + assert_eq!( + ActiveProtocolState::::get().subperiod(), + Subperiod::BuildAndEarn + ); + assert_eq!( + ActiveProtocolState::::get().period_number(), + snapshot_state.period_number(), + ); + } + // TODO: investigate why the PoV size is so large here, even after removing read of `IntegratedDApps` storage. // Relevant file: polkadot-sdk/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs // UPDATE: after some investigation, it seems that PoV size benchmarks are very unprecise // - the worst case measured is usually very far off the actual value that is consumed on chain. // There's an ongoing item to improve it (mentioned on roundtable meeting). - + // /// This benchmark isn't used directly in the runtime code, but it's convenient to do manual analysis of the benchmarked values. /// Tier assignment is a PoV heavy operation, and it has to be properly analyzed, independently from other weight items. #[benchmark] diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs index f99885c83d..c355d7ee99 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/utils.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -180,7 +180,10 @@ pub(super) fn max_number_of_contracts() -> u32 { T::MaxNumberOfContracts::get().min(NUMBER_OF_SLOTS).into() } -/// TODO +/// Registers & staked on the specified number of smart contracts +/// +/// Stake amounts are decided in such a way to maximize tier filling rate. +/// This means that all of the contracts should end up in some tier. pub(super) fn prepare_contracts_for_tier_assignment(x: u32) { let developer: T::AccountId = whitelisted_caller(); for id in 0..x { diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index e50ef2e249..34edc3afa2 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -74,9 +74,12 @@ const STAKING_ID: LockIdentifier = *b"dapstake"; const LOG_TARGET: &str = "dapp-staking"; -/// TODO +/// Helper enum for benchmarking. pub(crate) enum TierAssignment { + /// Real tier assignment calculation should be done. Real, + /// Dummy tier assignment calculation should be done, e.g. default value should be returned. + #[cfg(feature = "runtime-benchmarks")] Dummy, } @@ -1268,7 +1271,6 @@ pub mod pallet { ) -> DispatchResult { Self::ensure_pallet_enabled()?; - // TODO: Shall we make sure only dApp owner or beneficiary can trigger the claim? let _ = ensure_signed(origin)?; let dapp_info = @@ -1661,7 +1663,7 @@ pub mod pallet { .unwrap_or_default() } - /// TODO + /// Used to handle era & period transitions. pub(crate) fn era_and_period_handler( now: BlockNumber, tier_assignment: TierAssignment, @@ -1727,14 +1729,17 @@ pub mod pallet { dapp_reward_pool, }; - // TODO: docs! // Distribute dapps into tiers, write it into storage + // + // To help with benchmarking, it's possible to omit real tier calculation use `Dummy` approach instead. + // This must never be used in production code, obviously. let dapp_tier_rewards = match tier_assignment { TierAssignment::Real => Self::get_dapp_tier_assignment( current_era, protocol_state.period_number(), dapp_reward_pool, ), + #[cfg(feature = "runtime-benchmarks")] TierAssignment::Dummy => DAppTierRewardsFor::::default(), }; DAppTiers::::insert(¤t_era, dapp_tier_rewards); From bfa3013bb0b0d739fb91e80cea7bd79678f4e5e9 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 14:56:21 +0100 Subject: [PATCH 10/30] Full benchmarks integration --- .../dapp-staking-v3/src/benchmarking/mod.rs | 5 +- pallets/dapp-staking-v3/src/lib.rs | 47 ++- pallets/dapp-staking-v3/src/test/tests.rs | 6 +- pallets/dapp-staking-v3/src/weights.rs | 306 +++++++++++------- 4 files changed, 230 insertions(+), 134 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index 899fb3efef..314539b13a 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -881,9 +881,6 @@ mod benchmarks { // UPDATE: after some investigation, it seems that PoV size benchmarks are very unprecise // - the worst case measured is usually very far off the actual value that is consumed on chain. // There's an ongoing item to improve it (mentioned on roundtable meeting). - // - /// This benchmark isn't used directly in the runtime code, but it's convenient to do manual analysis of the benchmarked values. - /// Tier assignment is a PoV heavy operation, and it has to be properly analyzed, independently from other weight items. #[benchmark] fn dapp_tier_assignment(x: Linear<0, { max_number_of_contracts::() }>) { // Prepare init config (protocol state, tier params & config, etc.) @@ -899,7 +896,7 @@ mod benchmarks { #[block] { - let dapp_tiers = + let (dapp_tiers, _) = Pallet::::get_dapp_tier_assignment(reward_era, reward_period, reward_pool); // TODO: how to move this outside of the 'block'? Cannot declare it outside, and then use it inside. assert_eq!(dapp_tiers.dapps.len(), x as usize); diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 34edc3afa2..ff04a518b7 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1572,17 +1572,21 @@ pub mod pallet { /// after which the tier reward pool is divided by the number of available slots in the tier. /// /// The returned object contains information about each dApp that made it into a tier. + /// Alongside tier assignment info, number of read DB contract stake entries is returned. pub(crate) fn get_dapp_tier_assignment( era: EraNumber, period: PeriodNumber, dapp_reward_pool: Balance, - ) -> DAppTierRewardsFor { + ) -> (DAppTierRewardsFor, DAppId) { let mut dapp_stakes = Vec::with_capacity(T::MaxNumberOfContracts::get() as usize); // 1. // Iterate over all staked dApps. // This is bounded by max amount of dApps we allow to be registered. + let mut counter = 0; for (dapp_id, stake_amount) in ContractStake::::iter() { + 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, @@ -1655,12 +1659,15 @@ pub mod pallet { // 6. // Prepare and return tier & rewards info. // In case rewards creation fails, we just write the default value. This should never happen though. - DAppTierRewards::::new( - dapp_tiers, - tier_rewards, - period, + ( + DAppTierRewards::::new( + dapp_tiers, + tier_rewards, + period, + ) + .unwrap_or_default(), + counter, ) - .unwrap_or_default() } /// Used to handle era & period transitions. @@ -1670,16 +1677,19 @@ pub mod pallet { ) -> Weight { let mut protocol_state = ActiveProtocolState::::get(); + // `ActiveProtocolState` is whitelisted, so we need to account for its read. + let mut consumed_weight = T::DbWeight::get().reads(1); + // We should not modify pallet storage while in maintenance mode. // This is a safety measure, since maintenance mode is expected to be // enabled in case some misbehavior or corrupted storage is detected. if protocol_state.maintenance { - return T::DbWeight::get().reads(1); + return consumed_weight; } // Nothing to do if it's not new era if !protocol_state.is_new_era(now) { - return T::DbWeight::get().reads(1); + return consumed_weight; } // At this point it's clear that an era change will happen @@ -1712,6 +1722,9 @@ pub mod pallet { let next_tier_config = NextTierConfig::::take(); TierConfig::::put(next_tier_config); + consumed_weight + .saturating_accrue(T::WeightInfo::on_initialize_voting_to_build_and_earn()); + ( Some(Event::::NewSubperiod { subperiod: protocol_state.subperiod(), @@ -1733,17 +1746,20 @@ pub mod pallet { // // To help with benchmarking, it's possible to omit real tier calculation use `Dummy` approach instead. // This must never be used in production code, obviously. - let dapp_tier_rewards = match tier_assignment { + let (dapp_tier_rewards, counter) = match tier_assignment { TierAssignment::Real => Self::get_dapp_tier_assignment( current_era, protocol_state.period_number(), dapp_reward_pool, ), #[cfg(feature = "runtime-benchmarks")] - TierAssignment::Dummy => DAppTierRewardsFor::::default(), + TierAssignment::Dummy => (DAppTierRewardsFor::::default(), 0), }; DAppTiers::::insert(¤t_era, dapp_tier_rewards); + consumed_weight + .saturating_accrue(T::WeightInfo::dapp_tier_assignment(counter.into())); + // Switch to `Voting` period if conditions are met. if protocol_state.period_info.is_next_period(next_era) { // Store info about period end @@ -1777,6 +1793,10 @@ pub mod pallet { TierConfig::::get().calculate_new(average_price, &tier_params); NextTierConfig::::put(new_tier_config); + consumed_weight.saturating_accrue( + T::WeightInfo::on_initialize_build_and_earn_to_voting(), + ); + ( Some(Event::::NewSubperiod { subperiod: protocol_state.subperiod(), @@ -1790,6 +1810,10 @@ pub mod pallet { era_info.migrate_to_next_era(None); + consumed_weight.saturating_accrue( + T::WeightInfo::on_initialize_build_and_earn_to_build_and_earn(), + ); + (None, era_reward) } } @@ -1818,8 +1842,7 @@ pub mod pallet { Self::deposit_event(period_event); } - // TODO: benchmark later - T::DbWeight::get().reads_writes(3, 3) + consumed_weight } } } diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index e2de5de36f..0e88dc5152 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -2110,7 +2110,7 @@ fn get_dapp_tier_assignment_basic_example_works() { // Finally, the actual test let protocol_state = ActiveProtocolState::::get(); let dapp_reward_pool = 1000000; - let tier_assignment = DappStaking::get_dapp_tier_assignment( + let (tier_assignment, counter) = DappStaking::get_dapp_tier_assignment( protocol_state.era + 1, protocol_state.period_number(), dapp_reward_pool, @@ -2125,6 +2125,7 @@ fn get_dapp_tier_assignment_basic_example_works() { number_of_smart_contracts as usize - 1, "One contract doesn't make it into any tier." ); + assert_eq!(counter, number_of_smart_contracts); // 1st tier checks let (entry_1, entry_2) = (tier_assignment.dapps[0], tier_assignment.dapps[1]); @@ -2187,7 +2188,7 @@ fn get_dapp_tier_assignment_zero_slots_per_tier_works() { // Calculate tier assignment (we don't need dApps for this test) let protocol_state = ActiveProtocolState::::get(); let dapp_reward_pool = 1000000; - let tier_assignment = DappStaking::get_dapp_tier_assignment( + let (tier_assignment, counter) = DappStaking::get_dapp_tier_assignment( protocol_state.era, protocol_state.period_number(), dapp_reward_pool, @@ -2198,6 +2199,7 @@ fn get_dapp_tier_assignment_zero_slots_per_tier_works() { assert_eq!(tier_assignment.period, protocol_state.period_number()); assert_eq!(tier_assignment.rewards.len(), number_of_tiers as usize); assert!(tier_assignment.dapps.is_empty()); + assert!(counter.is_zero()); assert!( tier_assignment.rewards[0].is_zero(), diff --git a/pallets/dapp-staking-v3/src/weights.rs b/pallets/dapp-staking-v3/src/weights.rs index 9ed97ee431..d8891c7115 100644 --- a/pallets/dapp-staking-v3/src/weights.rs +++ b/pallets/dapp-staking-v3/src/weights.rs @@ -20,7 +20,7 @@ //! Autogenerated weights for pallet_dapp_staking_v3 //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Dinos-MacBook-Pro.local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -56,7 +56,6 @@ pub trait WeightInfo { fn unregister() -> Weight; fn lock() -> Weight; fn unlock() -> Weight; - fn full_unlock() -> Weight; fn claim_unlocked(x: u32, ) -> Weight; fn relock_unlocking() -> Weight; fn stake() -> Weight; @@ -68,6 +67,9 @@ pub trait WeightInfo { fn unstake_from_unregistered() -> Weight; fn cleanup_expired_entries(x: u32, ) -> Weight; fn force() -> Weight; + fn on_initialize_voting_to_build_and_earn() -> Weight; + fn on_initialize_build_and_earn_to_voting() -> Weight; + fn on_initialize_build_and_earn_to_build_and_earn() -> Weight; fn dapp_tier_assignment(x: u32, ) -> Weight; } @@ -78,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) } /// Storage: DappStaking IntegratedDApps (r:1 w:1) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) @@ -92,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `3093` // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3093) + Weight::from_parts(18_000_000, 3093) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -102,7 +104,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3093` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(13_000_000, 3093) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -114,7 +116,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `76` // Estimated: `3093` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3093) + Weight::from_parts(14_000_000, 3093) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,8 +128,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3093` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3093) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(19_000_000, 3093) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -144,7 +146,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `12` // Estimated: `4764` // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) + Weight::from_parts(43_000_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -160,25 +162,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `163` // Estimated: `4764` - // Minimum execution time: 36_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: DappStaking Ledger (r:1 w:1) - /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: DappStaking CurrentEraInfo (r:1 w:1) - /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) - fn full_unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `163` - // Estimated: `4764` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(44_000_000, 4764) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(43_000_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -191,14 +176,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: DappStaking CurrentEraInfo (r:1 w:1) /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) /// The range of component `x` is `[0, 3]`. - fn claim_unlocked(x: u32, ) -> Weight { + fn claim_unlocked(_x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `160 + x * (17 ±0)` // Estimated: `4764` - // Minimum execution time: 32_000_000 picoseconds. - Weight::from_parts(35_583_071, 4764) - // Standard Error: 69_897 - .saturating_add(Weight::from_parts(1_471_498, 0).saturating_mul(x.into())) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(40_955_543, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -215,7 +198,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `174` // Estimated: `4764` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 4764) + Weight::from_parts(40_000_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -237,8 +220,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `258` // Estimated: `4764` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(45_000_000, 4764) + // Minimum execution time: 45_000_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)) } @@ -260,7 +243,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `437` // Estimated: `4764` - // Minimum execution time: 49_000_000 picoseconds. + // Minimum execution time: 48_000_000 picoseconds. Weight::from_parts(54_000_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -280,10 +263,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `485 + x * (8 ±0)` // Estimated: `4764` - // Minimum execution time: 49_000_000 picoseconds. - Weight::from_parts(55_476_077, 4764) - // Standard Error: 72_725 - .saturating_add(Weight::from_parts(4_049_981, 0).saturating_mul(x.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(51_664_058, 4764) + // Standard Error: 15_971 + .saturating_add(Weight::from_parts(4_243_613, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -300,10 +283,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `438 + x * (8 ±0)` // Estimated: `4764` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(47_715_646, 4764) - // Standard Error: 41_836 - .saturating_add(Weight::from_parts(4_504_988, 0).saturating_mul(x.into())) + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(48_357_596, 4764) + // Standard Error: 16_408 + .saturating_add(Weight::from_parts(4_302_059, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -315,8 +298,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `158` // Estimated: `3603` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(42_000_000, 3603) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_000_000, 3603) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -328,8 +311,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1086` // Estimated: `3948` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(50_000_000, 3948) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(41_000_000, 3948) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -349,8 +332,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `397` // Estimated: `4764` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(48_000_000, 4764) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(47_000_000, 4764) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -367,10 +350,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250 + x * (75 ±0)` // Estimated: `4764 + x * (2613 ±0)` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(40_563_259, 4764) - // Standard Error: 133_516 - .saturating_add(Weight::from_parts(6_899_171, 0).saturating_mul(x.into())) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(38_854_143, 4764) + // Standard Error: 54_134 + .saturating_add(Weight::from_parts(7_359_116, 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)) @@ -384,6 +367,61 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 9_000_000 picoseconds. Weight::from_parts(10_000_000, 0) } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking NextTierConfig (r:1 w:1) + /// Proof: DappStaking NextTierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:0 w:1) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + fn on_initialize_voting_to_build_and_earn() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `3870` + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(24_000_000, 3870) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking StaticTierParams (r:1 w:0) + /// Proof: DappStaking StaticTierParams (max_values: Some(1), max_size: Some(167), added: 662, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:1 w:0) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// 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(483), added: 2958, mode: MaxEncodedLen) + /// Storage: DappStaking NextTierConfig (r:0 w:1) + /// Proof: DappStaking NextTierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + fn on_initialize_build_and_earn_to_voting() -> Weight { + // Proof Size summary in bytes: + // Measured: `685` + // Estimated: `3870` + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(37_000_000, 3870) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking DAppTiers (r:0 w:1) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(483), added: 2958, mode: MaxEncodedLen) + fn on_initialize_build_and_earn_to_build_and_earn() -> Weight { + // Proof Size summary in bytes: + // Measured: `73` + // Estimated: `3870` + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3870) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } /// Storage: DappStaking ContractStake (r:101 w:0) /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) /// Storage: DappStaking TierConfig (r:1 w:0) @@ -394,9 +432,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `158 + x * (33 ±0)` // Estimated: `3063 + x * (2073 ±0)` // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(15_026_604, 3063) - // Standard Error: 6_050 - .saturating_add(Weight::from_parts(2_666_223, 0).saturating_mul(x.into())) + Weight::from_parts(12_709_998, 3063) + // Standard Error: 8_047 + .saturating_add(Weight::from_parts(2_731_946, 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, 2073).saturating_mul(x.into())) @@ -409,8 +447,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) } /// Storage: DappStaking IntegratedDApps (r:1 w:1) /// Proof: DappStaking IntegratedDApps (max_values: Some(65535), max_size: Some(123), added: 2103, mode: MaxEncodedLen) @@ -423,7 +461,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `3093` // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3093) + Weight::from_parts(18_000_000, 3093) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -433,7 +471,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3093` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(13_000_000, 3093) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -445,7 +483,7 @@ impl WeightInfo for () { // Measured: `76` // Estimated: `3093` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3093) + Weight::from_parts(14_000_000, 3093) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -457,8 +495,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3093` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3093) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(19_000_000, 3093) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -475,7 +513,7 @@ impl WeightInfo for () { // Measured: `12` // Estimated: `4764` // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) + Weight::from_parts(43_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -491,25 +529,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `163` // Estimated: `4764` - // Minimum execution time: 36_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: DappStaking Ledger (r:1 w:1) - /// Proof: DappStaking Ledger (max_values: None, max_size: Some(250), added: 2725, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: DappStaking CurrentEraInfo (r:1 w:1) - /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) - fn full_unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `163` - // Estimated: `4764` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(44_000_000, 4764) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(43_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -522,14 +543,12 @@ impl WeightInfo for () { /// Storage: DappStaking CurrentEraInfo (r:1 w:1) /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) /// The range of component `x` is `[0, 3]`. - fn claim_unlocked(x: u32, ) -> Weight { + fn claim_unlocked(_x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `160 + x * (17 ±0)` // Estimated: `4764` - // Minimum execution time: 32_000_000 picoseconds. - Weight::from_parts(35_583_071, 4764) - // Standard Error: 69_897 - .saturating_add(Weight::from_parts(1_471_498, 0).saturating_mul(x.into())) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(40_955_543, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -546,7 +565,7 @@ impl WeightInfo for () { // Measured: `174` // Estimated: `4764` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 4764) + Weight::from_parts(40_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -568,8 +587,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `258` // Estimated: `4764` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(45_000_000, 4764) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(49_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -591,7 +610,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `437` // Estimated: `4764` - // Minimum execution time: 49_000_000 picoseconds. + // Minimum execution time: 48_000_000 picoseconds. Weight::from_parts(54_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -611,10 +630,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `485 + x * (8 ±0)` // Estimated: `4764` - // Minimum execution time: 49_000_000 picoseconds. - Weight::from_parts(55_476_077, 4764) - // Standard Error: 72_725 - .saturating_add(Weight::from_parts(4_049_981, 0).saturating_mul(x.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(51_664_058, 4764) + // Standard Error: 15_971 + .saturating_add(Weight::from_parts(4_243_613, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -631,10 +650,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `438 + x * (8 ±0)` // Estimated: `4764` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(47_715_646, 4764) - // Standard Error: 41_836 - .saturating_add(Weight::from_parts(4_504_988, 0).saturating_mul(x.into())) + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(48_357_596, 4764) + // Standard Error: 16_408 + .saturating_add(Weight::from_parts(4_302_059, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -646,8 +665,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `158` // Estimated: `3603` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(42_000_000, 3603) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_000_000, 3603) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -659,8 +678,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1086` // Estimated: `3948` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(50_000_000, 3948) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(41_000_000, 3948) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -680,8 +699,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `397` // Estimated: `4764` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(48_000_000, 4764) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(47_000_000, 4764) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -698,10 +717,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250 + x * (75 ±0)` // Estimated: `4764 + x * (2613 ±0)` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(40_563_259, 4764) - // Standard Error: 133_516 - .saturating_add(Weight::from_parts(6_899_171, 0).saturating_mul(x.into())) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(38_854_143, 4764) + // Standard Error: 54_134 + .saturating_add(Weight::from_parts(7_359_116, 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)) @@ -715,6 +734,61 @@ impl WeightInfo for () { // Minimum execution time: 9_000_000 picoseconds. Weight::from_parts(10_000_000, 0) } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking NextTierConfig (r:1 w:1) + /// Proof: DappStaking NextTierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:0 w:1) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + fn on_initialize_voting_to_build_and_earn() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `3870` + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(24_000_000, 3870) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking StaticTierParams (r:1 w:0) + /// Proof: DappStaking StaticTierParams (max_values: Some(1), max_size: Some(167), added: 662, mode: MaxEncodedLen) + /// Storage: DappStaking TierConfig (r:1 w:0) + /// Proof: DappStaking TierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// 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(483), added: 2958, mode: MaxEncodedLen) + /// Storage: DappStaking NextTierConfig (r:0 w:1) + /// Proof: DappStaking NextTierConfig (max_values: Some(1), max_size: Some(161), added: 656, mode: MaxEncodedLen) + fn on_initialize_build_and_earn_to_voting() -> Weight { + // Proof Size summary in bytes: + // Measured: `685` + // Estimated: `3870` + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(37_000_000, 3870) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: DappStaking CurrentEraInfo (r:1 w:1) + /// Proof: DappStaking CurrentEraInfo (max_values: Some(1), max_size: Some(112), added: 607, mode: MaxEncodedLen) + /// Storage: DappStaking EraRewards (r:1 w:1) + /// Proof: DappStaking EraRewards (max_values: None, max_size: Some(405), added: 2880, mode: MaxEncodedLen) + /// Storage: DappStaking DAppTiers (r:0 w:1) + /// Proof: DappStaking DAppTiers (max_values: None, max_size: Some(483), added: 2958, mode: MaxEncodedLen) + fn on_initialize_build_and_earn_to_build_and_earn() -> Weight { + // Proof Size summary in bytes: + // Measured: `73` + // Estimated: `3870` + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3870) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } /// Storage: DappStaking ContractStake (r:101 w:0) /// Proof: DappStaking ContractStake (max_values: Some(65535), max_size: Some(93), added: 2073, mode: MaxEncodedLen) /// Storage: DappStaking TierConfig (r:1 w:0) @@ -725,9 +799,9 @@ impl WeightInfo for () { // Measured: `158 + x * (33 ±0)` // Estimated: `3063 + x * (2073 ±0)` // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(15_026_604, 3063) - // Standard Error: 6_050 - .saturating_add(Weight::from_parts(2_666_223, 0).saturating_mul(x.into())) + Weight::from_parts(12_709_998, 3063) + // Standard Error: 8_047 + .saturating_add(Weight::from_parts(2_731_946, 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, 2073).saturating_mul(x.into())) From 5d03ad8a15ab52e4d78f7030d60fa6f5df51342c Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 15:14:45 +0100 Subject: [PATCH 11/30] Testing primitives --- pallets/dapp-staking-v3/src/lib.rs | 2 +- pallets/dapp-staking-v3/src/test/mock.rs | 5 ++--- pallets/inflation/src/mock.rs | 7 +++---- primitives/src/lib.rs | 3 +++ primitives/src/testing.rs | 24 ++++++++++++++++++++++++ 5 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 primitives/src/testing.rs diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index ff04a518b7..9873e29b4d 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1744,7 +1744,7 @@ pub mod pallet { // Distribute dapps into tiers, write it into storage // - // To help with benchmarking, it's possible to omit real tier calculation use `Dummy` approach instead. + // To help with benchmarking, it's possible to omit real tier calculation using the `Dummy` approach. // This must never be used in production code, obviously. let (dapp_tier_rewards, counter) = match tier_assignment { TierAssignment::Real => Self::get_dapp_tier_assignment( diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 2847e126dd..5dd43f4226 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -32,12 +32,11 @@ use sp_arithmetic::fixed_point::FixedU64; use sp_core::H256; use sp_io::TestExternalities; use sp_runtime::{ - generic::Header, // TODO: create testing primitives & move it there? traits::{BlakeTwo256, IdentityLookup}, Permill, }; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{testing::Header, Balance, BlockNumber}; pub(crate) type AccountId = u64; @@ -78,7 +77,7 @@ impl frame_system::Config for Test { type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; - type Header = Header; + type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type DbWeight = (); diff --git a/pallets/inflation/src/mock.rs b/pallets/inflation/src/mock.rs index a2c0af4b6a..3cac1bca84 100644 --- a/pallets/inflation/src/mock.rs +++ b/pallets/inflation/src/mock.rs @@ -32,13 +32,12 @@ use frame_support::{ use sp_core::H256; use sp_runtime::{ - generic::Header, // TODO: create testing primitives & move it there? traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, Perquintill, }; -use astar_primitives::{Balance, BlockNumber}; -pub(crate) type AccountId = u64; // TODO: might also be nice to have this under testing primitives? +use astar_primitives::{testing::Header, Balance, BlockNumber}; +pub(crate) type AccountId = u64; /// Initial inflation params set by the mock. pub const INIT_PARAMS: InflationParameters = InflationParameters { @@ -86,7 +85,7 @@ impl frame_system::Config for Test { type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; - type Header = Header; + type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type DbWeight = (); diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 010feba290..95b956872d 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -35,6 +35,9 @@ pub mod evm; /// Precompiles pub mod precompiles; +/// Useful primitives for testing. +pub mod testing; + /// Benchmark primitives #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks; diff --git a/primitives/src/testing.rs b/primitives/src/testing.rs new file mode 100644 index 0000000000..aa800582f1 --- /dev/null +++ b/primitives/src/testing.rs @@ -0,0 +1,24 @@ +// 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 . + +use super::BlockNumber; + +use sp_runtime::{generic::Header as GenericHeader, traits::BlakeTwo256}; + +/// Test `Header` type aligned with Astar primitives. +pub type Header = GenericHeader; From 230f67b1beb6a3baefaa725b6f2cbbd485575964 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 15:20:32 +0100 Subject: [PATCH 12/30] staking primitives --- pallets/inflation/src/lib.rs | 68 ++-------------------------- primitives/src/dapp_staking.rs | 81 ++++++++++++++++++++++++++++++++++ primitives/src/lib.rs | 3 ++ 3 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 primitives/src/dapp_staking.rs diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index e19841c71d..4ee5c76ebc 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -22,7 +22,10 @@ pub use pallet::*; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{ + dapp_staking::{CycleConfiguration, StakingRewardHandler}, + Balance, BlockNumber, +}; use frame_support::{pallet_prelude::*, traits::Currency}; use frame_system::{ensure_root, pallet_prelude::*}; use sp_runtime::{traits::CheckedAdd, Perquintill}; @@ -510,66 +513,3 @@ pub trait PayoutPerBlock { /// Payout reward to the collator responsible for producing the block. fn collators(reward: Imbalance); } - -// TODO: This should be moved to primitives. -// TODO2: However this ends up looking in the end, we should not duplicate these parameters in the runtime. -// Both the dApp staking & inflation pallet should use the same source. -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; - - /// 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; - - /// 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; - - /// How many blocks are there per standard era. - /// - /// This value has to be at least 1. - fn blocks_per_era() -> u32; - - /// For how many standard era lengths does the period last. - fn eras_per_period() -> u32 { - 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 { - Self::eras_per_period().saturating_mul(Self::periods_per_cycle()) - } - - /// How many blocks are there per cycle (a 'year'). - fn blocks_per_cycle() -> u32 { - Self::blocks_per_era().saturating_mul(Self::eras_per_cycle()) - } - - /// For how many standard era lengths do all the build&earn subperiods in a cycle last. - fn build_and_earn_eras_per_cycle() -> u32 { - Self::eras_per_build_and_earn_subperiod().saturating_mul(Self::periods_per_cycle()) - } -} - -// TODO: This should be moved to primitives. -/// Interface for staking reward handler. -/// -/// Provides reward pool values for stakers - normal & bonus rewards, as well as dApp reward pool. -/// Also provides a safe function for paying out rewards. -pub trait StakingRewardHandler { - /// Returns the staker reward pool & dApp reward pool for an era. - /// - /// The total staker reward pool is dynamic and depends on the total value staked. - fn staker_and_dapp_reward_pools(total_value_staked: Balance) -> (Balance, Balance); - - /// Returns the bonus reward pool for a period. - fn bonus_reward_pool() -> Balance; - - /// Attempts to pay out the rewards to the beneficiary. - fn payout_reward(beneficiary: &AccountId, reward: Balance) -> Result<(), ()>; -} diff --git a/primitives/src/dapp_staking.rs b/primitives/src/dapp_staking.rs new file mode 100644 index 0000000000..e5946b4aec --- /dev/null +++ b/primitives/src/dapp_staking.rs @@ -0,0 +1,81 @@ +// 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 . + +use super::Balance; + +// TODO2: However this ends up looking in the end, we should not duplicate these parameters in the runtime. +// Both the dApp staking & inflation pallet should use the same source. +/// TODO: docs! +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; + + /// 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; + + /// 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; + + /// How many blocks are there per standard era. + /// + /// This value has to be at least 1. + fn blocks_per_era() -> u32; + + /// For how many standard era lengths does the period last. + fn eras_per_period() -> u32 { + 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 { + Self::eras_per_period().saturating_mul(Self::periods_per_cycle()) + } + + /// How many blocks are there per cycle (a 'year'). + fn blocks_per_cycle() -> u32 { + Self::blocks_per_era().saturating_mul(Self::eras_per_cycle()) + } + + /// For how many standard era lengths do all the build&earn subperiods in a cycle last. + fn build_and_earn_eras_per_cycle() -> u32 { + Self::eras_per_build_and_earn_subperiod().saturating_mul(Self::periods_per_cycle()) + } +} + +/// Interface for staking reward handler. +/// +/// Provides reward pool values for stakers - normal & bonus rewards, as well as dApp reward pool. +/// Also provides a safe function for paying out rewards. +pub trait StakingRewardHandler { + /// Returns the staker reward pool & dApp reward pool for an era. + /// + /// The total staker reward pool is dynamic and depends on the total value staked. + fn staker_and_dapp_reward_pools(total_value_staked: Balance) -> (Balance, Balance); + + /// Returns the bonus reward pool for a period. + fn bonus_reward_pool() -> Balance; + + /// Attempts to pay out the rewards to the beneficiary. + fn payout_reward(beneficiary: &AccountId, reward: Balance) -> Result<(), ()>; +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 95b956872d..a531b87334 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -35,6 +35,9 @@ pub mod evm; /// Precompiles pub mod precompiles; +/// dApp staking & inflation primitives. +pub mod dapp_staking; + /// Useful primitives for testing. pub mod testing; From b770d65825b3d40ef94dd75e305c39c6320bb68e Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 17:15:53 +0100 Subject: [PATCH 13/30] dev fix --- pallets/dapp-staking-v3/src/lib.rs | 2 +- runtime/local/src/lib.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 9873e29b4d..86069c4528 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -169,7 +169,7 @@ pub mod pallet { #[pallet::constant] type UnlockingPeriod: Get; - /// Maximum amount of stake contract entries acount is allowed to have at once. + /// Maximum amount of stake contract entries an account is allowed to have at once. #[pallet::constant] type MaxNumberOfStakedContracts: Get; diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 52717d0048..3aa60f0f89 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -63,8 +63,9 @@ use sp_runtime::{ use sp_std::prelude::*; pub use astar_primitives::{ - evm::EvmRevertCodeHandler, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, - Index, Signature, + dapp_staking::{CycleConfiguration, StakingRewardHandler}, + evm::EvmRevertCodeHandler, + AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature, }; pub use pallet_block_rewards_hybrid::RewardDistributionConfig; @@ -577,7 +578,7 @@ impl pallet_inflation::PayoutPerBlock for InflationPayoutPerB } pub struct InflationCycleConfig; -impl pallet_inflation::CycleConfiguration for InflationCycleConfig { +impl CycleConfiguration for InflationCycleConfig { fn periods_per_cycle() -> u32 { 4 } From 0671b8c49e3d7c3a4b1e29e03642aeb2e14406a6 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 17:31:38 +0100 Subject: [PATCH 14/30] Integration part1 --- pallets/dapp-staking-v3/src/lib.rs | 18 +++++++++++------- pallets/dapp-staking-v3/src/test/mock.rs | 15 +++++++++++---- pallets/dapp-staking-v3/src/types.rs | 18 ------------------ runtime/local/src/lib.rs | 15 +-------------- 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 86069c4528..b9ee68029e 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -52,7 +52,10 @@ use sp_runtime::{ }; pub use sp_std::vec::Vec; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{ + dapp_staking::{CycleConfiguration, StakingRewardHandler}, + Balance, BlockNumber, +}; pub use pallet::*; @@ -64,7 +67,7 @@ mod benchmarking; mod types; use types::*; -pub use types::{PriceProvider, RewardPoolProvider, TierThreshold}; +pub use types::{PriceProvider, TierThreshold}; pub mod weights; pub use weights::WeightInfo; @@ -125,8 +128,8 @@ pub mod pallet { /// Used to provide price information about the native token. type NativePriceProvider: PriceProvider; - /// Used to provide reward pools amount. - type RewardPoolProvider: RewardPoolProvider; + /// Used to handle reward payouts & reward pool amount fetching. + type StakingRewardHandler: StakingRewardHandler; /// Length of a standard era in block numbers. #[pallet::constant] @@ -1734,11 +1737,12 @@ pub mod pallet { ) } Subperiod::BuildAndEarn => { + let staked = era_info.total_staked_amount(); let (staker_reward_pool, dapp_reward_pool) = - T::RewardPoolProvider::normal_reward_pools(); + T::StakingRewardHandler::staker_and_dapp_reward_pools(staked); let era_reward = EraReward { staker_reward_pool, - staked: era_info.total_staked_amount(), + staked, dapp_reward_pool, }; @@ -1763,7 +1767,7 @@ pub mod pallet { // Switch to `Voting` period if conditions are met. if protocol_state.period_info.is_next_period(next_era) { // Store info about period end - let bonus_reward_pool = T::RewardPoolProvider::bonus_reward_pool(); + let bonus_reward_pool = T::StakingRewardHandler::bonus_reward_pool(); PeriodEnd::::insert( &protocol_state.period_number(), PeriodEndInfo { diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 5dd43f4226..c65fc01c43 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -115,17 +115,24 @@ impl PriceProvider for DummyPriceProvider { } } -pub struct DummyRewardPoolProvider; -impl RewardPoolProvider for DummyRewardPoolProvider { - fn normal_reward_pools() -> (Balance, Balance) { +pub struct DummyStakingRewardHandler; +impl StakingRewardHandler for DummyStakingRewardHandler { + fn staker_and_dapp_reward_pools(_total_staked_value: Balance) -> (Balance, Balance) { ( Balance::from(1_000_000_000_000_u128), Balance::from(1_000_000_000_u128), ) } + fn bonus_reward_pool() -> Balance { Balance::from(3_000_000_u128) } + + fn payout_reward(beneficiary: &AccountId, reward: Balance) -> Result<(), ()> { + // TODO: add an option for this to fail, so we can test it + let _ = Balances::deposit_creating(beneficiary, reward); + Ok(()) + } } #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, Hash)] @@ -155,7 +162,7 @@ impl pallet_dapp_staking::Config for Test { type SmartContract = MockSmartContract; type ManagerOrigin = frame_system::EnsureRoot; type NativePriceProvider = DummyPriceProvider; - type RewardPoolProvider = DummyRewardPoolProvider; + type StakingRewardHandler = DummyStakingRewardHandler; type StandardEraLength = ConstU32<10>; type StandardErasPerVotingSubperiod = ConstU32<8>; type StandardErasPerBuildAndEarnSubperiod = ConstU32<16>; diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 0cd7cc7c18..14047e06c3 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -1707,21 +1707,3 @@ pub trait PriceProvider { /// Get the price of the native token. fn average_price() -> FixedU64; } - -// TODO: however the implementation ends up looking, -// it should consider total staked amount when filling up the bonus pool. -// This is to ensure bonus rewards aren't too large in case there is little amount of staked funds. -pub trait RewardPoolProvider { - /// Get the reward pools for stakers and dApps. - /// - /// TODO: discussion about below - /// The assumption is that the underlying implementation keeps track of how often this is called. - /// E.g. let's assume it's supposed to be called at the end of each era. - /// In case era is forced, it will last shorter. If pallet is put into maintenance mode, era might last longer. - /// Reward should adjust to that accordingly. - /// Alternative is to provide number of blocks for which era lasted. - fn normal_reward_pools() -> (Balance, Balance); - - /// Get the bonus pool for stakers. - fn bonus_reward_pool() -> Balance; -} diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 3aa60f0f89..b3118443f3 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -512,19 +512,6 @@ impl pallet_dapp_staking_v3::PriceProvider for DummyPriceProvider { } } -pub struct DummyRewardPoolProvider; -impl pallet_dapp_staking_v3::RewardPoolProvider for DummyRewardPoolProvider { - fn normal_reward_pools() -> (Balance, Balance) { - ( - Balance::from(1_000_000_000_000 * AST), - Balance::from(1_000_000_000 * AST), - ) - } - fn bonus_reward_pool() -> Balance { - Balance::from(3_000_000 * AST) - } -} - #[cfg(feature = "runtime-benchmarks")] pub struct BenchmarkHelper(sp_std::marker::PhantomData); #[cfg(feature = "runtime-benchmarks")] @@ -548,7 +535,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type SmartContract = SmartContract; type ManagerOrigin = frame_system::EnsureRoot; type NativePriceProvider = DummyPriceProvider; - type RewardPoolProvider = DummyRewardPoolProvider; + type StakingRewardHandler = Inflation; type StandardEraLength = StandardEraLength; type StandardErasPerVotingSubperiod = StandardErasPerVotingSubperiod; type StandardErasPerBuildAndEarnSubperiod = StandardErasPerBuildAndEarnSubperiod; From f8ddfc66c682472e06f602e6a845652f3113ca63 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 17:49:48 +0100 Subject: [PATCH 15/30] Integration part2 --- .../dapp-staking-v3/src/benchmarking/utils.rs | 4 +- pallets/dapp-staking-v3/src/lib.rs | 31 ++++------- pallets/dapp-staking-v3/src/test/mock.rs | 51 +++++++++++++------ .../dapp-staking-v3/src/test/testing_utils.rs | 16 +++--- pallets/dapp-staking-v3/src/test/tests.rs | 10 ++-- primitives/src/dapp_staking.rs | 6 +-- runtime/local/src/lib.rs | 18 ++----- 7 files changed, 69 insertions(+), 67 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs index c355d7ee99..55c9fb45f8 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/utils.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -108,8 +108,8 @@ pub(super) fn dapp_staking_events() -> Vec> { /// **NOTE:** This assumes similar tier configuration for all runtimes. /// If we decide to change this, we'll need to provide a more generic init function. pub(super) fn initial_config() { - let era_length = T::StandardEraLength::get(); - let voting_period_length_in_eras = T::StandardErasPerVotingSubperiod::get(); + let era_length = T::CycleConfiguration::blocks_per_era(); + let voting_period_length_in_eras = T::CycleConfiguration::eras_per_voting_subperiod(); // Init protocol state ActiveProtocolState::::put(ProtocolState { diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index b9ee68029e..9a3d7d64c8 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -131,20 +131,8 @@ pub mod pallet { /// Used to handle reward payouts & reward pool amount fetching. type StakingRewardHandler: StakingRewardHandler; - /// Length of a standard era in block numbers. - #[pallet::constant] - type StandardEraLength: Get; - - /// Length of the `Voting` subperiod in standard eras. - /// Although `Voting` subperiod only consumes one 'era', we still measure its length in standard eras - /// for the sake of simplicity & consistency. - #[pallet::constant] - type StandardErasPerVotingSubperiod: Get; - - /// Length of the `Build&Earn` subperiod in standard eras. - /// Each `Build&Earn` subperiod consists of one or more distinct standard eras. - #[pallet::constant] - type StandardErasPerBuildAndEarnSubperiod: Get; + /// Describes era length, subperiods & period length, as well as cycle length. + type CycleConfiguration: CycleConfiguration; /// Maximum length of a single era reward span length entry. #[pallet::constant] @@ -1520,8 +1508,8 @@ pub mod pallet { /// Returns the number of blocks per voting period. pub(crate) fn blocks_per_voting_period() -> BlockNumber { - T::StandardEraLength::get() - .saturating_mul(T::StandardErasPerVotingSubperiod::get().into()) + T::CycleConfiguration::blocks_per_era() + .saturating_mul(T::CycleConfiguration::eras_per_voting_subperiod().into()) } /// `true` if smart contract is active, `false` if it has been unregistered. @@ -1543,7 +1531,7 @@ pub mod pallet { /// Unlocking period expressed in the number of blocks. pub(crate) fn unlock_period() -> BlockNumber { - T::StandardEraLength::get().saturating_mul(T::UnlockingPeriod::get().into()) + T::CycleConfiguration::blocks_per_era().saturating_mul(T::UnlockingPeriod::get().into()) } /// Assign eligible dApps into appropriate tiers, and calculate reward for each tier. @@ -1710,10 +1698,10 @@ pub mod pallet { dapp_reward_pool: Balance::zero(), }; - let next_subperiod_start_era = - next_era.saturating_add(T::StandardErasPerBuildAndEarnSubperiod::get()); + let next_subperiod_start_era = next_era + .saturating_add(T::CycleConfiguration::eras_per_build_and_earn_subperiod()); let build_and_earn_start_block = - now.saturating_add(T::StandardEraLength::get()); + now.saturating_add(T::CycleConfiguration::blocks_per_era()); protocol_state.advance_to_next_subperiod( next_subperiod_start_era, build_and_earn_start_block, @@ -1809,7 +1797,8 @@ pub mod pallet { era_reward, ) } else { - let next_era_start_block = now.saturating_add(T::StandardEraLength::get()); + let next_era_start_block = + now.saturating_add(T::CycleConfiguration::blocks_per_era()); protocol_state.next_era_start = next_era_start_block; era_info.migrate_to_next_era(None); diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index c65fc01c43..4e62a334ab 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -156,6 +156,25 @@ impl crate::BenchmarkHelper for BenchmarkHelper u32 { + 4 + } + + fn eras_per_voting_subperiod() -> u32 { + 8 + } + + fn eras_per_build_and_earn_subperiod() -> u32 { + 16 + } + + fn blocks_per_era() -> u32 { + 10 + } +} + impl pallet_dapp_staking::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -163,9 +182,7 @@ impl pallet_dapp_staking::Config for Test { type ManagerOrigin = frame_system::EnsureRoot; type NativePriceProvider = DummyPriceProvider; type StakingRewardHandler = DummyStakingRewardHandler; - type StandardEraLength = ConstU32<10>; - type StandardErasPerVotingSubperiod = ConstU32<8>; - type StandardErasPerBuildAndEarnSubperiod = ConstU32<16>; + type CycleConfiguration = DummyCycleConfiguration; type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<10>; @@ -201,12 +218,9 @@ impl ExtBuilder { ext.execute_with(|| { System::set_block_number(1); - // Not sure why the mess with type happens here, but trait specification is needed to compile - let era_length: BlockNumber = - <::StandardEraLength as sp_core::Get<_>>::get(); - let voting_period_length_in_eras: EraNumber = - <::StandardErasPerVotingSubperiod as sp_core::Get<_>>::get( - ); + let era_length = ::CycleConfiguration::blocks_per_era(); + let voting_period_length_in_eras = + ::CycleConfiguration::eras_per_voting_subperiod(); // Init protocol state pallet_dapp_staking::ActiveProtocolState::::put(ProtocolState { @@ -234,7 +248,6 @@ impl ExtBuilder { era: 2, period: 1, }, - }); // Init tier params @@ -254,9 +267,18 @@ impl ExtBuilder { ]) .unwrap(), tier_thresholds: BoundedVec::try_from(vec![ - TierThreshold::DynamicTvlAmount { amount: 100, minimum_amount: 80 }, - TierThreshold::DynamicTvlAmount { amount: 50, minimum_amount: 40 }, - TierThreshold::DynamicTvlAmount { amount: 20, minimum_amount: 20 }, + TierThreshold::DynamicTvlAmount { + amount: 100, + minimum_amount: 80, + }, + TierThreshold::DynamicTvlAmount { + amount: 50, + minimum_amount: 40, + }, + TierThreshold::DynamicTvlAmount { + amount: 20, + minimum_amount: 20, + }, TierThreshold::FixedTvlAmount { amount: 15 }, ]) .unwrap(), @@ -275,8 +297,7 @@ impl ExtBuilder { pallet_dapp_staking::NextTierConfig::::put(init_tier_config); DappStaking::on_initialize(System::block_number()); - } - ); + }); ext } diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 2923ab0586..9b65022440 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -28,7 +28,7 @@ use frame_support::{assert_ok, traits::Get}; use sp_runtime::{traits::Zero, Perbill}; use std::collections::HashMap; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{dapp_staking::CycleConfiguration, Balance, BlockNumber}; /// Helper struct used to store the entire pallet state snapshot. /// Used when comparison of before/after states is required. @@ -1151,15 +1151,15 @@ pub(crate) fn assert_block_bump(pre_snapshot: &MemorySnapshot) { "Voting subperiod only lasts for a single era." ); - let eras_per_bep: EraNumber = - ::StandardErasPerBuildAndEarnSubperiod::get(); + let eras_per_bep = + ::CycleConfiguration::eras_per_build_and_earn_subperiod(); assert_eq!( post_protoc_state.period_info.next_subperiod_start_era, post_protoc_state.era + eras_per_bep, "Build&earn must last for the predefined amount of standard eras." ); - let standard_era_length: BlockNumber = ::StandardEraLength::get(); + let standard_era_length = ::CycleConfiguration::blocks_per_era(); assert_eq!( post_protoc_state.next_era_start, current_block_number + standard_era_length, @@ -1184,10 +1184,10 @@ pub(crate) fn assert_block_bump(pre_snapshot: &MemorySnapshot) { "Voting era must last for a single era." ); - let blocks_per_standard_era: BlockNumber = - ::StandardEraLength::get(); - let eras_per_voting_subperiod: EraNumber = - ::StandardErasPerVotingSubperiod::get(); + let blocks_per_standard_era = + ::CycleConfiguration::blocks_per_era(); + let eras_per_voting_subperiod = + ::CycleConfiguration::eras_per_voting_subperiod(); let eras_per_voting_subperiod: BlockNumber = eras_per_voting_subperiod.into(); let era_length: BlockNumber = blocks_per_standard_era * eras_per_voting_subperiod; assert_eq!( diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 0e88dc5152..20b1f9aaba 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -18,7 +18,7 @@ use crate::test::{mock::*, testing_utils::*}; use crate::{ - pallet::Config, ActiveProtocolState, DAppId, EraNumber, EraRewards, Error, Event, ForcingType, + pallet::Config, ActiveProtocolState, DAppId, EraRewards, Error, Event, ForcingType, IntegratedDApps, Ledger, NextDAppId, PeriodNumber, StakerInfo, Subperiod, TierConfig, }; @@ -29,7 +29,7 @@ use frame_support::{ }; use sp_runtime::traits::Zero; -use astar_primitives::{Balance, BlockNumber}; +use astar_primitives::{dapp_staking::CycleConfiguration, Balance, BlockNumber}; #[test] fn maintenace_mode_works() { @@ -197,9 +197,9 @@ fn on_initialize_base_state_change_works() { assert_eq!(protocol_state.period_number(), 1); // Advance eras just until we reach the next voting period - let eras_per_bep_period: EraNumber = - ::StandardErasPerBuildAndEarnSubperiod::get(); - let blocks_per_era: BlockNumber = ::StandardEraLength::get(); + let eras_per_bep_period = + ::CycleConfiguration::eras_per_build_and_earn_subperiod(); + let blocks_per_era: BlockNumber = ::CycleConfiguration::blocks_per_era(); for era in 2..(2 + eras_per_bep_period - 1) { let pre_block = System::block_number(); advance_to_next_era(); diff --git a/primitives/src/dapp_staking.rs b/primitives/src/dapp_staking.rs index e5946b4aec..0e04c68b1c 100644 --- a/primitives/src/dapp_staking.rs +++ b/primitives/src/dapp_staking.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -use super::Balance; +use super::{Balance, BlockNumber}; // TODO2: However this ends up looking in the end, we should not duplicate these parameters in the runtime. // Both the dApp staking & inflation pallet should use the same source. @@ -40,7 +40,7 @@ pub trait CycleConfiguration { /// How many blocks are there per standard era. /// /// This value has to be at least 1. - fn blocks_per_era() -> u32; + fn blocks_per_era() -> BlockNumber; /// For how many standard era lengths does the period last. fn eras_per_period() -> u32 { @@ -53,7 +53,7 @@ pub trait CycleConfiguration { } /// How many blocks are there per cycle (a 'year'). - fn blocks_per_cycle() -> u32 { + fn blocks_per_cycle() -> BlockNumber { Self::blocks_per_era().saturating_mul(Self::eras_per_cycle()) } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index b3118443f3..8b77e2a3b2 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -523,12 +523,6 @@ impl pallet_dapp_staking_v3::BenchmarkHelper> } } -parameter_types! { - pub const StandardEraLength: BlockNumber = 30; // should be 1 minute per standard era - pub const StandardErasPerVotingSubperiod: u32 = 2; - pub const StandardErasPerBuildAndEarnSubperiod: u32 = 22; -} - impl pallet_dapp_staking_v3::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -536,9 +530,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type ManagerOrigin = frame_system::EnsureRoot; type NativePriceProvider = DummyPriceProvider; type StakingRewardHandler = Inflation; - type StandardEraLength = StandardEraLength; - type StandardErasPerVotingSubperiod = StandardErasPerVotingSubperiod; - type StandardErasPerBuildAndEarnSubperiod = StandardErasPerBuildAndEarnSubperiod; + type CycleConfiguration = InflationCycleConfig; type EraRewardSpanLength = ConstU32<8>; type RewardRetentionInPeriods = ConstU32<2>; type MaxNumberOfContracts = ConstU32<100>; @@ -571,15 +563,15 @@ impl CycleConfiguration for InflationCycleConfig { } fn eras_per_voting_subperiod() -> u32 { - StandardErasPerVotingSubperiod::get() + 2 } fn eras_per_build_and_earn_subperiod() -> u32 { - StandardErasPerBuildAndEarnSubperiod::get() + 22 } - fn blocks_per_era() -> u32 { - StandardEraLength::get() + fn blocks_per_era() -> BlockNumber { + 30 } } From ccdbf242de3a9376e36cea2cf804e4dab0fe6c5f Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Fri, 1 Dec 2023 18:25:49 +0100 Subject: [PATCH 16/30] Reward payout integration --- pallets/dapp-staking-v3/src/lib.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 9a3d7d64c8..3eafab990c 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -327,6 +327,8 @@ pub mod pallet { InternalUnstakeError, /// Rewards are no longer claimable since they are too old. RewardExpired, + /// Reward payout has failed due to an unexpected reason. + RewardPayoutFailed, /// There are no claimable rewards. NoClaimableRewards, /// An unexpected error occured while trying to claim staker rewards. @@ -1165,10 +1167,8 @@ pub mod pallet { } let rewards_len: u32 = rewards.len().unique_saturated_into(); - // TODO: add extra layer of security here to prevent excessive minting. Probably via Tokenomics2.0 pallet. - // Account exists since it has locked funds. - T::Currency::deposit_into_existing(&account, reward_sum) - .map_err(|_| Error::::InternalClaimStakerError)?; + T::StakingRewardHandler::payout_reward(&account, reward_sum) + .map_err(|_| Error::::RewardPayoutFailed)?; Self::update_ledger(&account, ledger); @@ -1234,10 +1234,8 @@ pub mod pallet { Perbill::from_rational(eligible_amount, period_end_info.total_vp_stake) * period_end_info.bonus_reward_pool; - // TODO: add extra layer of security here to prevent excessive minting. Probably via Tokenomics2.0 pallet. - // Account exists since it has locked funds. - T::Currency::deposit_into_existing(&account, bonus_reward) - .map_err(|_| Error::::InternalClaimStakerError)?; + T::StakingRewardHandler::payout_reward(&account, bonus_reward) + .map_err(|_| Error::::RewardPayoutFailed)?; // Cleanup entry since the reward has been claimed StakerInfo::::remove(&account, &smart_contract); @@ -1262,6 +1260,7 @@ pub mod pallet { ) -> DispatchResult { Self::ensure_pallet_enabled()?; + // To keep in line with legacy behavior, dApp rewards can be claimed by anyone. let _ = ensure_signed(origin)?; let dapp_info = @@ -1289,8 +1288,8 @@ pub mod pallet { // Get reward destination, and deposit the reward. let beneficiary = dapp_info.reward_beneficiary(); - // TODO: add extra layer of security here to prevent excessive minting. Probably via Tokenomics2.0 pallet. - T::Currency::deposit_creating(beneficiary, amount); + T::StakingRewardHandler::payout_reward(&beneficiary, amount) + .map_err(|_| Error::::RewardPayoutFailed)?; // Write back updated struct to prevent double reward claims DAppTiers::::insert(&era, dapp_tiers); From 3bd862207d236f1bae2b96db9f455ca87508052f Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Sat, 2 Dec 2023 13:34:58 +0100 Subject: [PATCH 17/30] Replace lock functionality with freeze --- .../dapp-staking-v3/src/benchmarking/mod.rs | 26 +++---- .../dapp-staking-v3/src/benchmarking/utils.rs | 2 +- pallets/dapp-staking-v3/src/lib.rs | 71 ++++++++++++------- pallets/dapp-staking-v3/src/test/mock.rs | 25 +++++-- .../dapp-staking-v3/src/test/testing_utils.rs | 4 ++ runtime/local/src/lib.rs | 23 +++--- 6 files changed, 95 insertions(+), 56 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index 314539b13a..8684137b15 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -159,7 +159,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); #[extrinsic_call] _(RawOrigin::Signed(staker.clone()), amount); @@ -187,7 +187,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get() * 2; - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -212,7 +212,7 @@ mod benchmarks { let amount = (T::MinimumStakeAmount::get() + 1) * Into::::into(max_number_of_contracts::()) + Into::::into(T::MaxUnlockingChunks::get()); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -299,7 +299,7 @@ mod benchmarks { let amount = T::MinimumLockedAmount::get() * 2 + Into::::into(T::MaxUnlockingChunks::get()); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -342,7 +342,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -379,7 +379,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get() + 1; - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -426,7 +426,7 @@ mod benchmarks { // Lock some amount by the staker let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -481,7 +481,7 @@ mod benchmarks { // Lock & stake some amount by the staker let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -536,7 +536,7 @@ mod benchmarks { // Lock & stake some amount by the staker let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -575,7 +575,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get() * 1000 * UNIT; - T::Currency::make_free_balance_be(&owner, amount); + T::BenchmarkHelper::set_balance(&owner, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(owner.clone()).into(), amount, @@ -598,7 +598,7 @@ mod benchmarks { )); let staker: T::AccountId = account("staker", idx.into(), SEED); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -660,7 +660,7 @@ mod benchmarks { )); let amount = T::MinimumLockedAmount::get(); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, @@ -701,7 +701,7 @@ mod benchmarks { let staker: T::AccountId = whitelisted_caller(); let amount = T::MinimumLockedAmount::get() * Into::::into(T::MaxNumberOfStakedContracts::get()); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, diff --git a/pallets/dapp-staking-v3/src/benchmarking/utils.rs b/pallets/dapp-staking-v3/src/benchmarking/utils.rs index 55c9fb45f8..688f964a76 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/utils.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/utils.rs @@ -199,7 +199,7 @@ pub(super) fn prepare_contracts_for_tier_assignment(x: u32) { let mut amount = 1000 * MIN_TIER_THRESHOLD; for id in 0..x { let staker = account("staker", id.into(), 1337); - T::Currency::make_free_balance_be(&staker, amount); + T::BenchmarkHelper::set_balance(&staker, amount); assert_ok!(DappStaking::::lock( RawOrigin::Signed(staker.clone()).into(), amount, diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 3eafab990c..95a5e71f71 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -42,7 +42,10 @@ use frame_support::{ pallet_prelude::*, - traits::{Currency, LockIdentifier, LockableCurrency, StorageVersion, WithdrawReasons}, + traits::{ + fungible::{Inspect as FunInspect, MutateFreeze as FunMutateFreeze}, + StorageVersion, + }, weights::Weight, }; use frame_system::pallet_prelude::*; @@ -72,9 +75,6 @@ pub use types::{PriceProvider, TierThreshold}; pub mod weights; pub use weights::WeightInfo; -// Lock identifier for the dApp staking pallet -const STAKING_ID: LockIdentifier = *b"dapstake"; - const LOG_TARGET: &str = "dapp-staking"; /// Helper enum for benchmarking. @@ -98,8 +98,10 @@ pub mod pallet { pub struct Pallet(_); #[cfg(feature = "runtime-benchmarks")] - pub trait BenchmarkHelper { + pub trait BenchmarkHelper { fn get_smart_contract(id: u32) -> SmartContract; + + fn set_balance(account: &AccountId, balance: Balance); } #[pallet::config] @@ -109,13 +111,14 @@ pub mod pallet { + IsType<::RuntimeEvent> + TryInto>; + /// The overarching freeze reason. + type RuntimeFreezeReason: From; + /// Currency used for staking. - /// TODO: remove usage of deprecated LockableCurrency trait and use the new freeze approach. Might require some renaming of Lock to Freeze :) - // https://github.com/paritytech/substrate/pull/12951/ - // Look at nomination pools implementation for reference! - type Currency: LockableCurrency< + /// Reference: https://github.com/paritytech/substrate/pull/12951/ + type Currency: FunMutateFreeze< Self::AccountId, - Moment = Self::BlockNumber, + Id = Self::RuntimeFreezeReason, Balance = Balance, >; @@ -177,7 +180,7 @@ pub mod pallet { /// Helper trait for benchmarks. #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: BenchmarkHelper; + type BenchmarkHelper: BenchmarkHelper; } #[pallet::event] @@ -521,6 +524,14 @@ pub mod pallet { } } + /// A reason for freezing funds. + #[pallet::composite_enum] + pub enum FreezeReason { + /// Account is participating in dApp staking. + #[codec(index = 0)] + DAppStaking, + } + #[pallet::call] impl Pallet { /// Used to enable or disable maintenance mode. @@ -717,7 +728,7 @@ pub mod pallet { // Calculate & check amount available for locking let available_balance = - T::Currency::free_balance(&account).saturating_sub(ledger.active_locked_amount()); + T::Currency::balance(&account).saturating_sub(ledger.active_locked_amount()); let amount_to_lock = available_balance.min(amount); ensure!(!amount_to_lock.is_zero(), Error::::ZeroAmount); @@ -728,7 +739,7 @@ pub mod pallet { Error::::LockedAmountBelowThreshold ); - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; CurrentEraInfo::::mutate(|era_info| { era_info.add_locked(amount_to_lock); }); @@ -785,7 +796,7 @@ pub mod pallet { .map_err(|_| Error::::TooManyUnlockingChunks)?; // Update storage - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; CurrentEraInfo::::mutate(|era_info| { era_info.unlocking_started(amount_to_unlock); }); @@ -819,7 +830,7 @@ pub mod pallet { 0 }; - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; CurrentEraInfo::::mutate(|era_info| { era_info.unlocking_removed(amount); }); @@ -847,7 +858,7 @@ pub mod pallet { Error::::LockedAmountBelowThreshold ); - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; CurrentEraInfo::::mutate(|era_info| { era_info.add_locked(amount); era_info.unlocking_removed(amount); @@ -971,7 +982,7 @@ pub mod pallet { // 5. // Update remaining storage entries - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; StakerInfo::::insert(&account, &smart_contract, new_staking_info); ContractStake::::insert(&dapp_info.id, contract_stake_info); @@ -1082,7 +1093,7 @@ pub mod pallet { StakerInfo::::insert(&account, &smart_contract, new_staking_info); } - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; Self::deposit_event(Event::::Unstake { account, @@ -1170,7 +1181,7 @@ pub mod pallet { T::StakingRewardHandler::payout_reward(&account, reward_sum) .map_err(|_| Error::::RewardPayoutFailed)?; - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; rewards.into_iter().for_each(|(era, reward)| { Self::deposit_event(Event::::Reward { @@ -1362,7 +1373,7 @@ pub mod pallet { // Seems wrong because it serves as discentive for unstaking & moving over to a new contract. // Update remaining storage entries - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; StakerInfo::::remove(&account, &smart_contract); Self::deposit_event(Event::::UnstakeFromUnregistered { @@ -1419,7 +1430,7 @@ pub mod pallet { .contract_stake_count .saturating_reduce(entries_to_delete.unique_saturated_into()); ledger.maybe_cleanup_expired(threshold_period); // Not necessary but we do it for the sake of consistency - Self::update_ledger(&account, ledger); + Self::update_ledger(&account, ledger)?; Self::deposit_event(Event::::ExpiredEntriesRemoved { account, @@ -1490,19 +1501,25 @@ pub mod pallet { /// Update the account ledger, and dApp staking balance lock. /// /// In case account ledger is empty, entries from the DB are removed and lock is released. - pub(crate) fn update_ledger(account: &T::AccountId, ledger: AccountLedgerFor) { + pub(crate) fn update_ledger( + account: &T::AccountId, + ledger: AccountLedgerFor, + ) -> Result<(), DispatchError> { if ledger.is_empty() { Ledger::::remove(&account); - T::Currency::remove_lock(STAKING_ID, account); + T::Currency::thaw(&FreezeReason::DAppStaking.into(), account)?; } else { - T::Currency::set_lock( - STAKING_ID, + T::Currency::set_freeze( + &FreezeReason::DAppStaking.into(), account, ledger.active_locked_amount(), - WithdrawReasons::all(), - ); + )?; Ledger::::insert(account, ledger); } + + // TODO: DOCS! + + Ok(()) } /// Returns the number of blocks per voting period. diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index 4e62a334ab..dec06bba82 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -24,7 +24,10 @@ use crate::{ use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU128, ConstU32}, + traits::{ + fungible::{Mutate as FunMutate, Unbalanced as FunUnbalanced}, + ConstU128, ConstU32, + }, weights::Weight, }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -102,9 +105,9 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU128; type AccountStore = System; type HoldIdentifier = (); - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type MaxFreezes = ConstU32<1>; type WeightInfo = (); } @@ -130,7 +133,7 @@ impl StakingRewardHandler for DummyStakingRewardHandler { fn payout_reward(beneficiary: &AccountId, reward: Balance) -> Result<(), ()> { // TODO: add an option for this to fail, so we can test it - let _ = Balances::deposit_creating(beneficiary, reward); + let _ = Balances::mint_into(beneficiary, reward); Ok(()) } } @@ -148,12 +151,19 @@ impl Default for MockSmartContract { } #[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkHelper(sp_std::marker::PhantomData); +pub struct BenchmarkHelper(sp_std::marker::PhantomData<(SC, ACC)>); #[cfg(feature = "runtime-benchmarks")] -impl crate::BenchmarkHelper for BenchmarkHelper { +impl crate::BenchmarkHelper + for BenchmarkHelper +{ fn get_smart_contract(id: u32) -> MockSmartContract { MockSmartContract::Wasm(id as AccountId) } + + fn set_balance(account: &AccountId, amount: Balance) { + Balances::write_balance(account, amount) + .expect("Must succeed in test/benchmark environment."); + } } pub struct DummyCycleConfiguration; @@ -177,6 +187,7 @@ impl CycleConfiguration for DummyCycleConfiguration { impl pallet_dapp_staking::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type SmartContract = MockSmartContract; type ManagerOrigin = frame_system::EnsureRoot; @@ -194,7 +205,7 @@ impl pallet_dapp_staking::Config for Test { type NumberOfTiers = ConstU32<4>; type WeightInfo = weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = BenchmarkHelper; + type BenchmarkHelper = BenchmarkHelper; } pub struct ExtBuilder; diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index 9b65022440..b914ec7ffa 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -231,6 +231,8 @@ pub(crate) fn assert_lock(account: AccountId, amount: Balance) { pre_snapshot.current_era_info.total_locked + expected_lock_amount, "Total locked balance should be increased by the amount locked." ); + + // TODO: test that frozen amount has been increased } /// Start the unlocking process for locked funds and assert success. @@ -312,6 +314,8 @@ pub(crate) fn assert_unlock(account: AccountId, amount: Balance) { .saturating_sub(expected_unlock_amount), post_era_info.total_locked ); + + // TODO: test that frozen amount has been decreased } /// Claims the unlocked funds back into free balance of the user and assert success. diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 8b77e2a3b2..ff2bed54ad 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -28,8 +28,9 @@ use astar_primitives::evm::HashedDefaultMappings; use frame_support::{ construct_runtime, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Currency, EitherOfDiverse, - EqualPrivilegeOnly, FindAuthor, Get, InstanceFilter, Nothing, OnFinalize, WithdrawReasons, + fungible::Unbalanced as FunUnbalanced, AsEnsureOriginWithArg, ConstU128, ConstU32, + ConstU64, Currency, EitherOfDiverse, EqualPrivilegeOnly, FindAuthor, Get, InstanceFilter, + Nothing, OnFinalize, WithdrawReasons, }, weights::{ constants::{ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, @@ -297,9 +298,9 @@ impl pallet_balances::Config for Runtime { type AccountStore = System; type WeightInfo = weights::pallet_balances::SubstrateWeight; type HoldIdentifier = (); - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type MaxFreezes = ConstU32<1>; } parameter_types! { @@ -513,18 +514,24 @@ impl pallet_dapp_staking_v3::PriceProvider for DummyPriceProvider { } #[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkHelper(sp_std::marker::PhantomData); +pub struct BenchmarkHelper(sp_std::marker::PhantomData<(SC, ACC)>); #[cfg(feature = "runtime-benchmarks")] -impl pallet_dapp_staking_v3::BenchmarkHelper> - for BenchmarkHelper> +impl pallet_dapp_staking_v3::BenchmarkHelper, AccountId> + for BenchmarkHelper, AccountId> { fn get_smart_contract(id: u32) -> SmartContract { SmartContract::Wasm(AccountId::from([id as u8; 32])) } + + fn set_balance(account: &AccountId, amount: Balance) { + Balances::write_balance(account, amount) + .expect("Must succeed in test/benchmark environment."); + } } impl pallet_dapp_staking_v3::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type SmartContract = SmartContract; type ManagerOrigin = frame_system::EnsureRoot; @@ -542,7 +549,7 @@ impl pallet_dapp_staking_v3::Config for Runtime { type NumberOfTiers = ConstU32<4>; type WeightInfo = pallet_dapp_staking_v3::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = BenchmarkHelper>; + type BenchmarkHelper = BenchmarkHelper, AccountId>; } pub struct InflationPayoutPerBlock; From b6e2d533eb5dd46b58dda5d8e3e72d884c66d644 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 09:47:42 +0100 Subject: [PATCH 18/30] Cleanup TODOs --- pallets/dapp-staking-v3/src/lib.rs | 30 ++++++++++++---------------- pallets/dapp-staking-v3/src/types.rs | 7 +++---- runtime/local/src/lib.rs | 3 +-- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 95a5e71f71..847ac54624 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1369,9 +1369,6 @@ pub mod pallet { era_info.unstake_amount(amount, protocol_state.subperiod()); }); - // TODO: HOWEVER, we should not pay out bonus rewards for such contracts. - // Seems wrong because it serves as discentive for unstaking & moving over to a new contract. - // Update remaining storage entries Self::update_ledger(&account, ledger)?; StakerInfo::::remove(&account, &smart_contract); @@ -1498,9 +1495,12 @@ pub mod pallet { Ok(Some(who)) } - /// Update the account ledger, and dApp staking balance lock. + /// Update the account ledger, and dApp staking balance freeze. + /// + /// In case account ledger is empty, entries from the DB are removed and freeze is thawed. /// - /// In case account ledger is empty, entries from the DB are removed and lock is released. + /// This call can fail if the `freeze` or `thaw` operations fail. This should never happen since + /// runtime definition must ensure it supports necessary freezes. pub(crate) fn update_ledger( account: &T::AccountId, ledger: AccountLedgerFor, @@ -1517,8 +1517,6 @@ pub mod pallet { Ledger::::insert(account, ledger); } - // TODO: DOCS! - Ok(()) } @@ -1571,10 +1569,9 @@ pub mod pallet { /// else: /// exit loop since no more dApps will satisfy the threshold since they are sorted by score /// ``` + /// (Sort the entries by dApp ID, in ascending order. This is so we can efficiently search for them using binary search.) /// - /// 4. Sort the entries by dApp ID, in ascending order. This is so we can efficiently search for them using binary search. - /// - /// 5. Calculate rewards for each tier. + /// 4. Calculate rewards for each tier. /// This is done by dividing the total reward pool into tier reward pools, /// after which the tier reward pool is divided by the number of available slots in the tier. /// @@ -1643,13 +1640,12 @@ pub mod pallet { tier_id.saturating_inc(); } - // TODO: what if multiple dApps satisfy the tier entry threshold but there's not enough slots to accomodate them all? - - // 4. - // Sort by dApp ID, in ascending order (unstable sort should be faster, and stability is "guaranteed" due to lack of duplicated Ids). - dapp_tiers.sort_unstable_by(|first, second| first.dapp_id.cmp(&second.dapp_id)); + // In case when tier has 1 more free slot, but two dApps with exactly same score satisfy the threshold, + // one of them will be assigned to the tier, and the other one will be assigned to the lower tier, if it exists. + // + // There is no explicit definition of which dApp gets the advantage - it's decided by dApp IDs hash & the unstable sort algorithm. - // 5. Calculate rewards. + // 4. Calculate rewards. let tier_rewards = tier_config .reward_portion .iter() @@ -1663,7 +1659,7 @@ pub mod pallet { }) .collect::>(); - // 6. + // 5. // Prepare and return tier & rewards info. // In case rewards creation fails, we just write the default value. This should never happen though. ( diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 14047e06c3..92f31111cd 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -1352,9 +1352,6 @@ impl TierThreshold { Self::DynamicTvlAmount { amount, .. } => *amount, } } - - // TODO: maybe add a check that compares `Self` to another threshold and ensures it has lower requirements? - // Could be useful to have this check as a sanity check when params are configured. } /// Top level description of tier slot parameters used to calculate tier configuration. @@ -1637,7 +1634,9 @@ impl, NT: Get> DAppTierRewards { rewards: Vec, period: PeriodNumber, ) -> Result { - // TODO: should this part of the code ensure that dapps are sorted by Id? + // Sort by dApp ID, in ascending order (unstable sort should be faster, and stability is "guaranteed" due to lack of duplicated Ids). + let mut dapps = dapps; + dapps.sort_unstable_by(|first, second| first.dapp_id.cmp(&second.dapp_id)); let dapps = BoundedVec::try_from(dapps).map_err(|_| ())?; let rewards = BoundedVec::try_from(rewards).map_err(|_| ())?; diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index ff2bed54ad..f5e318d898 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -24,7 +24,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use astar_primitives::evm::HashedDefaultMappings; use frame_support::{ construct_runtime, parameter_types, traits::{ @@ -65,7 +64,7 @@ use sp_std::prelude::*; pub use astar_primitives::{ dapp_staking::{CycleConfiguration, StakingRewardHandler}, - evm::EvmRevertCodeHandler, + evm::{EvmRevertCodeHandler, HashedDefaultMappings}, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature, }; pub use pallet_block_rewards_hybrid::RewardDistributionConfig; From ee9ce2259a9a95d7070e1bd26ea7b565c8aa8331 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 10:12:54 +0100 Subject: [PATCH 19/30] More negative tests --- pallets/dapp-staking-v3/src/test/mock.rs | 17 ++++- pallets/dapp-staking-v3/src/test/tests.rs | 92 +++++++++++++++++++++++ 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index dec06bba82..050eb112f2 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -38,6 +38,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, Permill, }; +use sp_std::cell::RefCell; use astar_primitives::{testing::Header, Balance, BlockNumber}; @@ -118,6 +119,10 @@ impl PriceProvider for DummyPriceProvider { } } +thread_local! { + pub(crate) static DOES_PAYOUT_SUCCEED: RefCell = RefCell::new(false); +} + pub struct DummyStakingRewardHandler; impl StakingRewardHandler for DummyStakingRewardHandler { fn staker_and_dapp_reward_pools(_total_staked_value: Balance) -> (Balance, Balance) { @@ -132,9 +137,12 @@ impl StakingRewardHandler for DummyStakingRewardHandler { } fn payout_reward(beneficiary: &AccountId, reward: Balance) -> Result<(), ()> { - // TODO: add an option for this to fail, so we can test it - let _ = Balances::mint_into(beneficiary, reward); - Ok(()) + if DOES_PAYOUT_SUCCEED.with(|v| v.borrow().clone()) { + let _ = Balances::mint_into(beneficiary, reward); + Ok(()) + } else { + Err(()) + } } } @@ -211,6 +219,9 @@ impl pallet_dapp_staking::Config for Test { pub struct ExtBuilder; impl ExtBuilder { pub fn build() -> TestExternalities { + // Normal behavior is for reward payout to succeed + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = true); + let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 20b1f9aaba..cb457695ab 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -1401,6 +1401,34 @@ fn claim_staker_rewards_after_expiry_fails() { }) } +#[test] +fn claim_staker_rewards_fails_due_to_payout_failure() { + ExtBuilder::build().execute_with(|| { + // Register smart contract, lock&stake some amount + let smart_contract = MockSmartContract::default(); + assert_register(1, &smart_contract); + + let account = 2; + let amount = 300; + assert_lock(account, amount); + assert_stake(account, &smart_contract, amount); + + // Advance into Build&Earn period, and allow one era to pass. + advance_to_era(ActiveProtocolState::::get().era + 2); + + // Disable successfull reward payout + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); + assert_noop!( + DappStaking::claim_staker_rewards(RuntimeOrigin::signed(account)), + Error::::RewardPayoutFailed, + ); + + // Re-enable it again, claim should work again + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = true); + assert_claim_staker_rewards(account); + }) +} + #[test] fn claim_bonus_reward_works() { ExtBuilder::build().execute_with(|| { @@ -1555,6 +1583,34 @@ fn claim_bonus_reward_after_expiry_fails() { }) } +#[test] +fn claim_bonus_reward_fails_due_to_payout_failure() { + ExtBuilder::build().execute_with(|| { + // Register smart contract, lock&stake some amount + let smart_contract = MockSmartContract::default(); + assert_register(1, &smart_contract); + + let account = 2; + let amount = 300; + assert_lock(account, amount); + assert_stake(account, &smart_contract, amount); + + // Advance to next period so we can claim bonus reward + advance_to_next_period(); + + // Disable successfull reward payout + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); + assert_noop!( + DappStaking::claim_bonus_reward(RuntimeOrigin::signed(account), smart_contract), + Error::::RewardPayoutFailed, + ); + + // Re-enable it again, claim should work again + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = true); + assert_claim_bonus_reward(account, &smart_contract); + }) +} + #[test] fn claim_dapp_reward_works() { ExtBuilder::build().execute_with(|| { @@ -1696,6 +1752,42 @@ fn claim_dapp_reward_twice_for_same_era_fails() { }) } +#[test] +fn claim_dapp_fails_due_to_payout_failure() { + ExtBuilder::build().execute_with(|| { + // Register smart contract, lock&stake some amount + let smart_contract = MockSmartContract::default(); + assert_register(1, &smart_contract); + + let account = 2; + let amount = 300; + assert_lock(account, amount); + assert_stake(account, &smart_contract, amount); + + // Advance 2 eras so we have an entry for reward claiming + advance_to_era(ActiveProtocolState::::get().era + 2); + + // Disable successfull reward payout + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = false); + assert_noop!( + DappStaking::claim_dapp_reward( + RuntimeOrigin::signed(account), + smart_contract, + ActiveProtocolState::::get().era - 1 + ), + Error::::RewardPayoutFailed, + ); + + // Re-enable it again, claim should work again + DOES_PAYOUT_SUCCEED.with(|v| *v.borrow_mut() = true); + assert_claim_dapp_reward( + account, + &smart_contract, + ActiveProtocolState::::get().era - 1, + ); + }) +} + #[test] fn unstake_from_unregistered_is_ok() { ExtBuilder::build().execute_with(|| { From 42c4ec0ec1bf8953400127f4945da49642a4444f Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 10:32:26 +0100 Subject: [PATCH 20/30] Frozen balance test --- .../dapp-staking-v3/src/benchmarking/mod.rs | 2 +- .../dapp-staking-v3/src/test/testing_utils.rs | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index 8684137b15..7f9c3e7c49 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -876,7 +876,7 @@ mod benchmarks { ); } - // TODO: investigate why the PoV size is so large here, even after removing read of `IntegratedDApps` storage. + // Investigate why the PoV size is so large here, even after removing read of `IntegratedDApps` storage. // Relevant file: polkadot-sdk/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs // UPDATE: after some investigation, it seems that PoV size benchmarks are very unprecise // - the worst case measured is usually very far off the actual value that is consumed on chain. diff --git a/pallets/dapp-staking-v3/src/test/testing_utils.rs b/pallets/dapp-staking-v3/src/test/testing_utils.rs index b914ec7ffa..f20de522f1 100644 --- a/pallets/dapp-staking-v3/src/test/testing_utils.rs +++ b/pallets/dapp-staking-v3/src/test/testing_utils.rs @@ -20,11 +20,14 @@ use crate::test::mock::*; use crate::types::*; use crate::{ pallet::Config, ActiveProtocolState, ContractStake, CurrentEraInfo, DAppId, DAppTiers, - EraRewards, Event, IntegratedDApps, Ledger, NextDAppId, NextTierConfig, PeriodEnd, - PeriodEndInfo, StakerInfo, TierConfig, + EraRewards, Event, FreezeReason, IntegratedDApps, Ledger, NextDAppId, NextTierConfig, + PeriodEnd, PeriodEndInfo, StakerInfo, TierConfig, }; -use frame_support::{assert_ok, traits::Get}; +use frame_support::{ + assert_ok, + traits::{fungible::InspectFreeze, Get}, +}; use sp_runtime::{traits::Zero, Perbill}; use std::collections::HashMap; @@ -204,6 +207,8 @@ pub(crate) fn assert_lock(account: AccountId, amount: Balance) { let free_balance = Balances::free_balance(&account); let locked_balance = pre_snapshot.locked_balance(&account); + let init_frozen_balance = Balances::balance_frozen(&FreezeReason::DAppStaking.into(), &account); + let available_balance = free_balance .checked_sub(locked_balance) .expect("Locked amount cannot be greater than available free balance"); @@ -232,12 +237,16 @@ pub(crate) fn assert_lock(account: AccountId, amount: Balance) { "Total locked balance should be increased by the amount locked." ); - // TODO: test that frozen amount has been increased + assert_eq!( + init_frozen_balance + expected_lock_amount, + Balances::balance_frozen(&FreezeReason::DAppStaking.into(), &account) + ); } /// Start the unlocking process for locked funds and assert success. pub(crate) fn assert_unlock(account: AccountId, amount: Balance) { let pre_snapshot = MemorySnapshot::new(); + let init_frozen_balance = Balances::balance_frozen(&FreezeReason::DAppStaking.into(), &account); assert!( pre_snapshot.ledger.contains_key(&account), @@ -315,7 +324,10 @@ pub(crate) fn assert_unlock(account: AccountId, amount: Balance) { post_era_info.total_locked ); - // TODO: test that frozen amount has been decreased + assert_eq!( + init_frozen_balance - expected_unlock_amount, + Balances::balance_frozen(&FreezeReason::DAppStaking.into(), &account) + ); } /// Claims the unlocked funds back into free balance of the user and assert success. From 0569850f3003b83b4302965307458d9c1a605f24 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 12:06:45 +0100 Subject: [PATCH 21/30] Zero div --- pallets/dapp-staking-v3/src/types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 92f31111cd..77a1dc112d 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -1482,7 +1482,8 @@ impl> TiersConfiguration { /// Calculate new `TiersConfiguration`, based on the old settings, current native currency price and tier configuration. pub fn calculate_new(&self, native_price: FixedU64, params: &TierParameters) -> Self { - let new_number_of_slots = Self::calculate_number_of_slots(native_price); + // It must always be at least 1 slot. + let new_number_of_slots = Self::calculate_number_of_slots(native_price).max(1); // Calculate how much each tier gets slots. let new_slots_per_tier: Vec = params From 27c6f3d013ef90bf142dc3acc6ea2bdfd5b97b7b Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 14:42:55 +0100 Subject: [PATCH 22/30] Docs for inflation --- pallets/inflation/src/lib.rs | 81 +++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 4ee5c76ebc..a2d52e14a1 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -16,7 +16,86 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -//! TODO +//! # Inflation Handler Pallet +//! +//! ## Overview +//! +//! This pallet's main responsibility is handling inflation calculation & distribution. +//! +//! Inflation configuration is calculated periodically, according to the inflation parameters. +//! Based on this configuration, rewards are paid out - either per block or on demand. +//! +//! ## Cycles, Periods, Eras +//! +//! At the start of each cycle, the inflation configuration is recalculated. +//! +//! Cycle can be considered as a 'year' in the Astar network. +//! When cycle starts, inflation is calculated according to the total issuance at that point in time. +//! 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. +//! 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`. +//! Length of these subperiods is expressed in eras. An `era` is the core _time unit_ in dApp staking protocol. +//! When an era ends, in `Build&Earn` subperiod, rewards for dApps are calculated & assigned. +//! +//! Era's length is expressed in blocks. E.g. an era can last for 7200 blocks, which is approximately 1 day for 12 second block time. +//! +//! `Build&Earn` subperiod length is expressed in eras. E.g. if `Build&Earn` subperiod lasts for 5 eras, it means that during that subperiod, +//! dApp rewards will be calculated & assigned 5 times in total. Also, 5 distinct eras will change during that subperiod. If e.g. `Build&Earn` started at era 100, +//! with 5 eras per `Build&Earn` subperiod, then the subperiod will end at era 105. +//! +//! `Voting` subperiod always comes before `Build&Earn` subperiod. Its length is also expressed in eras, although it has to be interpreted a bit differently. +//! Even though `Voting` can last for more than 1 era in respect of length, it always takes exactly 1 era. +//! What this means is that if `Voting` lasts for 3 eras, and each era lasts 7200 blocks, then `Voting` will last for 21600 blocks. +//! But unlike `Build&Earn` subperiod, `Voting` will only take up one 'numerical' era. So if `Voting` starts at era 110, it will end at era 11. +//! +//! #### Example +//! * Cycle length: 4 periods +//! * `Voting` length: 10 eras +//! * `Build&Earn` length: 81 eras +//! * Era length: 7200 blocks +//! +//! This would mean that cycle lasts for roughly 364 days (4 * (10 + 81)). +//! +//! ## Recalculation +//! +//! When new cycle begins, inflation configuration is recalculated according to the inflation parameters & total issuance at that point in time. +//! Based on the max inflation rate, rewards for different network actors are calculated. +//! +//! Some rewards are calculated to be paid out per block, while some are per era or per period. +//! +//! ## Rewards +//! +//! ### Staker & Treasury Rewards +//! +//! These are paid out at the begininng of each block & are fixed amounts. +//! +//! ### Staker Rewards +//! +//! Staker rewards are paid out per staker, _on-demand_. +//! However, reward pool for an era is calculated at the end of each era. +//! +//! `era_reward_pool = base_staker_reward_pool_per_era + adjustable_staker_reward_pool_per_era` +//! +//! While the base staker reward pool is fixed, the adjustable part is calculated according to the total value staked & the ideal staking rate. +//! +//! ### dApp Rewards +//! +//! dApp rewards are paid out per dApp, _on-demand_. The reward is decided by the dApp staking protocol, or the tier system to be more precise. +//! This pallet only provides the total reward pool for all dApps per era. +//! +//! # Interface +//! +//! ## StakingRewardHandler +//! +//! This pallet implements `StakingRewardHandler` trait, which is used by the dApp staking protocol to get reward pools & distribute rewards. +//! + + + #![cfg_attr(not(feature = "std"), no_std)] From 6b4b84a046f297ac7351ac4ae13d5aad4fdde2c4 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 14:48:57 +0100 Subject: [PATCH 23/30] Rename is_active & add some more docs --- pallets/dapp-staking-v3/src/lib.rs | 15 +++++++++------ pallets/dapp-staking-v3/src/test/tests_types.rs | 6 +++--- pallets/dapp-staking-v3/src/types.rs | 4 ++-- pallets/inflation/src/lib.rs | 5 +---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 847ac54624..0d6b7d54ad 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -367,6 +367,9 @@ pub mod pallet { pub type NextDAppId = StorageValue<_, DAppId, ValueQuery>; /// Map of all dApps integrated into dApp staking protocol. + /// + /// Even though dApp is integrated, it does not mean it's still actively participating in dApp staking. + /// It might have been unregistered at some point in history. #[pallet::storage] pub type IntegratedDApps = CountedStorageMap< Hasher = Blake2_128Concat, @@ -891,7 +894,7 @@ pub mod pallet { let dapp_info = IntegratedDApps::::get(&smart_contract).ok_or(Error::::NotOperatedDApp)?; - ensure!(dapp_info.is_active(), Error::::NotOperatedDApp); + ensure!(dapp_info.is_registered(), Error::::NotOperatedDApp); let protocol_state = ActiveProtocolState::::get(); let current_era = protocol_state.era; @@ -1018,7 +1021,7 @@ pub mod pallet { let dapp_info = IntegratedDApps::::get(&smart_contract).ok_or(Error::::NotOperatedDApp)?; - ensure!(dapp_info.is_active(), Error::::NotOperatedDApp); + ensure!(dapp_info.is_registered(), Error::::NotOperatedDApp); let protocol_state = ActiveProtocolState::::get(); let current_era = protocol_state.era; @@ -1328,7 +1331,7 @@ pub mod pallet { let account = ensure_signed(origin)?; ensure!( - !Self::is_active(&smart_contract), + !Self::is_registered(&smart_contract), Error::::ContractStillActive ); @@ -1526,10 +1529,10 @@ pub mod pallet { .saturating_mul(T::CycleConfiguration::eras_per_voting_subperiod().into()) } - /// `true` if smart contract is active, `false` if it has been unregistered. - pub(crate) fn is_active(smart_contract: &T::SmartContract) -> bool { + /// `true` if smart contract is registered, `false` otherwise. + pub(crate) fn is_registered(smart_contract: &T::SmartContract) -> bool { IntegratedDApps::::get(smart_contract) - .map_or(false, |dapp_info| dapp_info.is_active()) + .map_or(false, |dapp_info| dapp_info.is_registered()) } /// Calculates the `EraRewardSpan` index for the specified era. diff --git a/pallets/dapp-staking-v3/src/test/tests_types.rs b/pallets/dapp-staking-v3/src/test/tests_types.rs index 054c69a6be..aadfbda6d1 100644 --- a/pallets/dapp-staking-v3/src/test/tests_types.rs +++ b/pallets/dapp-staking-v3/src/test/tests_types.rs @@ -169,11 +169,11 @@ fn dapp_info_basic_checks() { dapp_info.reward_destination = Some(beneficiary); assert_eq!(*dapp_info.reward_beneficiary(), beneficiary); - // Check if dApp is active - assert!(dapp_info.is_active()); + // Check if dApp is registered + assert!(dapp_info.is_registered()); dapp_info.state = DAppState::Unregistered(10); - assert!(!dapp_info.is_active()); + assert!(!dapp_info.is_registered()); } #[test] diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 77a1dc112d..3b18c7d7ac 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -284,8 +284,8 @@ impl DAppInfo { } } - /// `true` if dApp is still active (registered), `false` otherwise. - pub fn is_active(&self) -> bool { + /// `true` if dApp is registered, `false` otherwise. + pub fn is_registered(&self) -> bool { self.state == DAppState::Registered } } diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index a2d52e14a1..717aa764f1 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -74,7 +74,7 @@ //! These are paid out at the begininng of each block & are fixed amounts. //! //! ### Staker Rewards -//! +//! //! Staker rewards are paid out per staker, _on-demand_. //! However, reward pool for an era is calculated at the end of each era. //! @@ -94,9 +94,6 @@ //! This pallet implements `StakingRewardHandler` trait, which is used by the dApp staking protocol to get reward pools & distribute rewards. //! - - - #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; From 76d1e18dd9c91e904d7dd321a1379c647b2855f8 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 17:47:51 +0100 Subject: [PATCH 24/30] More docs --- primitives/src/dapp_staking.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/primitives/src/dapp_staking.rs b/primitives/src/dapp_staking.rs index 0e04c68b1c..92ead96b15 100644 --- a/primitives/src/dapp_staking.rs +++ b/primitives/src/dapp_staking.rs @@ -18,9 +18,13 @@ use super::{Balance, BlockNumber}; -// TODO2: However this ends up looking in the end, we should not duplicate these parameters in the runtime. -// Both the dApp staking & inflation pallet should use the same source. -/// TODO: docs! +/// 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. +/// * `period` - Period consists of two distinct subperiods: `Voting` & `Build&Earn`. They are integral parts of dApp staking. +/// Length is expressed in standard eras or just _eras_. +/// * `era` - Era is the basic time unit in the dApp staking protocol. At the end of each era, reward pools for stakers & dApps are calculated. +/// Era length is expressed in blocks. pub trait CycleConfiguration { /// How many different periods are there in a cycle (a 'year'). /// From 7332f75c8fdbeadde94d36a80863387a3032c9d6 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 18:49:26 +0100 Subject: [PATCH 25/30] pallet docs --- .../dapp-staking-v3/src/benchmarking/mod.rs | 1 - pallets/dapp-staking-v3/src/lib.rs | 24 ++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/pallets/dapp-staking-v3/src/benchmarking/mod.rs b/pallets/dapp-staking-v3/src/benchmarking/mod.rs index 7f9c3e7c49..4f9cbafdb9 100644 --- a/pallets/dapp-staking-v3/src/benchmarking/mod.rs +++ b/pallets/dapp-staking-v3/src/benchmarking/mod.rs @@ -898,7 +898,6 @@ mod benchmarks { { let (dapp_tiers, _) = Pallet::::get_dapp_tier_assignment(reward_era, reward_period, reward_pool); - // TODO: how to move this outside of the 'block'? Cannot declare it outside, and then use it inside. assert_eq!(dapp_tiers.dapps.len(), x as usize); } } diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 0d6b7d54ad..403a2eedd8 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -17,25 +17,20 @@ // along with Astar. If not, see . //! # dApp Staking v3 Pallet -//! TODO //! -//! - [`Config`] +//! For detailed high level documentation, please refer to the attached README.md file. +//! The crate level docs will cover overal pallet structure & implementation details. //! //! ## Overview //! -//! Pallet that implements dapps staking protocol. +//! Pallet that implements the dApp staking v3 protocol. +//! 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. //! -//! ## Interface -//! -//! ### Dispatchable Function -//! -//! <> -//! -//! ### Other -//! -//! <> +//! Rest of the pallet logic is concenrated in the lib.rs file. +//! This logic is tested in the `tests` module, with the help of extensive `testing_utils`. //! #![cfg_attr(not(feature = "std"), no_std)] @@ -86,6 +81,7 @@ pub(crate) enum TierAssignment { Dummy, } +#[doc = include_str!("../README.md")] #[frame_support::pallet] pub mod pallet { use super::*; @@ -115,7 +111,7 @@ pub mod pallet { type RuntimeFreezeReason: From; /// Currency used for staking. - /// Reference: https://github.com/paritytech/substrate/pull/12951/ + /// Reference: type Currency: FunMutateFreeze< Self::AccountId, Id = Self::RuntimeFreezeReason, From b20da61b4be30683d1074f5cd500e2066ce3b1e4 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 18:54:32 +0100 Subject: [PATCH 26/30] text --- pallets/dapp-staking-v3/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 403a2eedd8..ba332e69bd 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1560,7 +1560,7 @@ pub mod pallet { /// as well as the threshold for each tier. Threshold is the minimum amount of stake required to be eligible for a tier. /// Iterate over tier thresholds & capacities, starting from the top tier, and assign dApps to them. /// - /// ```ignore + /// ```text //// for each tier: /// for each unassigned dApp: /// if tier has capacity && dApp satisfies the tier threshold: From 4c32033aa00c772fb2d6c009139bfc40733cac86 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 18:59:55 +0100 Subject: [PATCH 27/30] scripts --- pallets/dapp-staking-v3/coverage_extrinsics.sh | 11 +++++++++++ .../{coverage.sh => coverage_types.sh} | 0 2 files changed, 11 insertions(+) create mode 100755 pallets/dapp-staking-v3/coverage_extrinsics.sh rename pallets/dapp-staking-v3/{coverage.sh => coverage_types.sh} (100%) diff --git a/pallets/dapp-staking-v3/coverage_extrinsics.sh b/pallets/dapp-staking-v3/coverage_extrinsics.sh new file mode 100755 index 0000000000..6d0c77b3f0 --- /dev/null +++ b/pallets/dapp-staking-v3/coverage_extrinsics.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +targets=("register" "unregister" "set_dapp_reward_beneficiary" "set_dapp_owner" "maintenance_mode" \ + "lock" "unlock" "claim_unlocked" "relock_unlocking" \ + "stake" "unstake" "claim_staker_rewards" "claim_bonus_reward" "claim_dapp_reward" \ + "unstake_from_unregistered" "cleanup_expired_entries" "force" ) + +for target in "${targets[@]}" +do + cargo tarpaulin -p pallet-dapp-staking-v3 -o=html --output-dir=./coverage/$target -- test::tests::$target +done \ No newline at end of file diff --git a/pallets/dapp-staking-v3/coverage.sh b/pallets/dapp-staking-v3/coverage_types.sh similarity index 100% rename from pallets/dapp-staking-v3/coverage.sh rename to pallets/dapp-staking-v3/coverage_types.sh From 453b7cd8d53c921cf8d3f4f9abffda10c8879741 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Mon, 4 Dec 2023 20:15:47 +0100 Subject: [PATCH 28/30] More tests --- pallets/dapp-staking-v3/src/lib.rs | 4 +- pallets/dapp-staking-v3/src/test/tests.rs | 73 ++++++++++++++++++++++- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index ba332e69bd..89ec801e53 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -1060,10 +1060,10 @@ pub mod pallet { ledger .unstake_amount(amount, current_era, protocol_state.period_info) .map_err(|err| match err { - // These are all defensive checks, which should never happen since we already checked them above. AccountLedgerError::InvalidPeriod | AccountLedgerError::InvalidEra => { Error::::UnclaimedRewards } + // This is a defensive check, which should never happen since we calculate the correct value above. AccountLedgerError::UnstakeAmountLargerThanStake => { Error::::UnstakeAmountTooLarge } @@ -1283,7 +1283,7 @@ pub mod pallet { // 'Consume' dApp reward for the specified era, if possible. let mut dapp_tiers = DAppTiers::::get(&era).ok_or(Error::::NoDAppTierInfo)?; ensure!( - Self::oldest_claimable_period(dapp_tiers.period) <= protocol_state.period_number(), + dapp_tiers.period >= Self::oldest_claimable_period(protocol_state.period_number()), Error::::RewardExpired ); diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index cb457695ab..f45009363f 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -925,7 +925,7 @@ fn stake_in_final_era_fails() { } #[test] -fn stake_fails_if_unclaimed_rewards_from_past_eras_remain() { +fn stake_fails_if_unclaimed_staker_rewards_from_past_remain() { ExtBuilder::build().execute_with(|| { // Register smart contract & lock some amount let smart_contract = MockSmartContract::default(); @@ -933,9 +933,43 @@ fn stake_fails_if_unclaimed_rewards_from_past_eras_remain() { assert_register(1, &smart_contract); assert_lock(account, 300); - // Stake some amount, then force next period + // Stake some amount, then force a few eras assert_stake(account, &smart_contract, 100); + advance_to_era(ActiveProtocolState::::get().era + 2); + + // Stake must fail due to unclaimed rewards + assert_noop!( + DappStaking::stake(RuntimeOrigin::signed(account), smart_contract, 100), + Error::::UnclaimedRewards + ); + + // Should also fail in the next period + advance_to_next_period(); + assert_noop!( + DappStaking::stake(RuntimeOrigin::signed(account), smart_contract, 100), + Error::::UnclaimedRewards + ); + }) +} + +#[test] +fn stake_fails_if_claimable_bonus_rewards_from_past_remain() { + ExtBuilder::build().execute_with(|| { + // Register smart contract, lock&stake some amount + let smart_contract = MockSmartContract::default(); + let account = 2; + assert_register(1, &smart_contract); + assert_lock(account, 300); + assert_stake(account, &smart_contract, 100); + + // Advance to next period, claim all staker rewards advance_to_next_period(); + for _ in 0..required_number_of_reward_claims(account) { + assert_claim_staker_rewards(account); + } + + // Try to stake again on the same contract, expect an error due to unclaimed bonus rewards + advance_to_era(ActiveProtocolState::::get().era + 2); assert_noop!( DappStaking::stake(RuntimeOrigin::signed(account), smart_contract, 100), Error::::UnclaimedRewards @@ -1225,6 +1259,9 @@ fn unstake_with_unclaimed_rewards_fails() { DappStaking::unstake(RuntimeOrigin::signed(account), smart_contract, 1), Error::::UnclaimedRewards ); + + // Advance to the next period, unstake should still fail. + advance_to_next_period(); }) } @@ -1753,7 +1790,37 @@ fn claim_dapp_reward_twice_for_same_era_fails() { } #[test] -fn claim_dapp_fails_due_to_payout_failure() { +fn claim_dapp_reward_for_expired_era_fails() { + ExtBuilder::build().execute_with(|| { + // Register smart contract, lock&stake some amount + let smart_contract = MockSmartContract::default(); + assert_register(1, &smart_contract); + + let account = 2; + let amount = 300; + assert_lock(account, amount); + assert_stake(account, &smart_contract, amount); + + let reward_retention_in_periods: PeriodNumber = + ::RewardRetentionInPeriods::get(); + + // Advance to period before the rewards expire. Claim reward must still work. + advance_to_period( + ActiveProtocolState::::get().period_number() + reward_retention_in_periods, + ); + assert_claim_dapp_reward(account, &smart_contract, 2); + + // Advance to the next era, expiring some rewards. + advance_to_next_period(); + assert_noop!( + DappStaking::claim_dapp_reward(RuntimeOrigin::signed(account), smart_contract, 3), + Error::::RewardExpired, + ); + }) +} + +#[test] +fn claim_dapp_reward_fails_due_to_payout_failure() { ExtBuilder::build().execute_with(|| { // Register smart contract, lock&stake some amount let smart_contract = MockSmartContract::default(); From f9b58583a95cfaf3e4d520831a56a8c0c47672cb Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Tue, 5 Dec 2023 08:32:19 +0100 Subject: [PATCH 29/30] Test, docs --- pallets/dapp-staking-v3/README.md | 30 +++++++++++++++++------ pallets/dapp-staking-v3/src/test/tests.rs | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/pallets/dapp-staking-v3/README.md b/pallets/dapp-staking-v3/README.md index afae398db2..72accbfc36 100644 --- a/pallets/dapp-staking-v3/README.md +++ b/pallets/dapp-staking-v3/README.md @@ -27,18 +27,22 @@ Each period consists of two subperiods: Each period is denoted by a number, which increments each time a new period begins. Period beginning is marked by the `voting` subperiod, after which follows the `build&earn` period. -Stakes are **only** valid throughout a period. When new period starts, all stakes are reset to zero. This helps prevent projects remaining staked due to intertia. +Stakes are **only** valid throughout a period. When new period starts, all stakes are reset to **zero**. This helps prevent projects remaining staked due to intertia of stakers, and makes for a more dynamic staking system. + +Even though stakes are reset, locks (or freezes) of tokens remain. #### Voting -When `Voting` starts, all _stakes_ are reset to **zero**. +When `Voting` subperiod starts, all _stakes_ are reset to **zero**. Projects participating in dApp staking are expected to market themselves to (re)attract stakers. Stakers must assess whether the project they want to stake on brings value to the ecosystem, and then `vote` for it. Casting a vote, or staking, during the `Voting` subperiod makes the staker eligible for bonus rewards. so they are encouraged to participate. `Voting` subperiod length is expressed in _standard_ era lengths, even though the entire voting period is treated as a single _voting era_. -E.g. if `voting` subperiod lasts for **10 eras**, and each era lasts for **100** blocks, total length of the `voting` subperiod will be **1000** blocks. +E.g. if `voting` subperiod lasts for **5 eras**, and each era lasts for **100** blocks, total length of the `voting` subperiod will be **500** blocks. +* Block 1, Era 1 starts, Period 1 starts, `Voting` subperiod starts +* Block 501, Era 2 starts, Period 1 continues, `Build&Earn` subperiod starts Neither stakers nor dApps earn rewards during this subperiod - no new rewards are generated after `voting` subperiod ends. @@ -51,6 +55,16 @@ After each _era_ ends, eligible stakers and dApps can claim the rewards they ear It is still possible to _stake_ during this period, and stakers are encouraged to do so since this will increase the rewards they earn. The only exemption is the **final era** of the `build&earn` subperiod - it's not possible to _stake_ then since the stake would be invalid anyhow (stake is only valid from the next era which would be in the next period). +To continue the previous example where era length is **100** blocks, let's assume that `Build&Earn` subperiod lasts for 10 eras: +* Block 1, Era 1 starts, Period 1 starts, `Voting` subperiod starts +* Block 501, Era 2 starts, Period 1 continues, `Build&Earn` subperiod starts +* Block 601, Era 3 starts, Period 1 continues, `Build&Earn` subperiod continues +* Block 701, Era 4 starts, Period 1 continues, `Build&Earn` subperiod continues +* ... +* Block 1401, Era 11 starts, Period 1 continues, `Build&Earn` subperiod enters the final era +* Block 1501, Era 12 starts, Period 2 starts, `Voting` subperiod starts +* Block 2001, Era 13 starts, Period 2 continues, `Build&Earn` subperiod starts + ### dApps & Smart Contracts Protocol is called dApp staking, but internally it essentially works with smart contracts, or even more precise, smart contract addresses. @@ -63,12 +77,14 @@ Projects, or _dApps_, must be registered into protocol to participate. Only a privileged `ManagerOrigin` can perform dApp registration. The pallet itself does not make assumptions who the privileged origin is, and it can differ from runtime to runtime. +Once dApp has been registered, stakers can stake on it immediatelly. + +When contract is registered, it is assigned a unique compact numeric Id - 16 bit unsigned integer. This is important for the inner workings of the pallet, and is not directly exposed to the users. + There is a limit of how many smart contracts can be registered at once. Once the limit is reached, any additional attempt to register a new contract will fail. #### Reward Beneficiary & Ownership -When contract is registered, it is assigned a unique compact numeric Id - 16 bit unsigned integer. This is important for the inner workings of the pallet, and is not directly exposed to the users. - After a dApp has been registered, it is possible to modify reward beneficiary or even the owner of the dApp. The owner can perform reward delegation and can further transfer ownership. #### Unregistration @@ -81,13 +97,13 @@ It's still possible however to claim past unclaimed rewards. Important to note that even if dApp has been unregistered, it still occupies a _slot_ in the dApp staking protocol and counts towards maximum number of registered dApps. -This will be improved in the future when dApp data will be cleaned up after the period ends. +This will be improved in the future when dApp data will be cleaned up after some time. ### Stakers #### Locking Tokens -In order for users to participate in dApp staking, the first step they need to take is lock some native currency. Reserved tokens cannot be locked, but tokens locked by another lock can be re-locked into dApp staking (double locked). +In order for users to participate in dApp staking, the first step they need to take is lock (or freeze) some native currency. Reserved tokens cannot be locked, but tokens locked by another lock can be re-locked into dApp staking (double locked). **NOTE:** Locked funds cannot be used for paying fees, or for transfer. diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index f45009363f..7f6f3d390b 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -66,6 +66,7 @@ fn maintenace_mode_call_filtering_works() { assert_ok!(DappStaking::maintenance_mode(RuntimeOrigin::root(), true)); assert!(ActiveProtocolState::::get().maintenance); + assert_storage_noop!(DappStaking::on_initialize(1)); assert_noop!( DappStaking::register(RuntimeOrigin::root(), 1, MockSmartContract::Wasm(1)), Error::::Disabled From 7edfa03d805852aa801dcdddb4b02812071e0bc4 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Tue, 5 Dec 2023 17:06:18 +0100 Subject: [PATCH 30/30] Review comment --- pallets/dapp-staking-v3/src/test/tests.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pallets/dapp-staking-v3/src/test/tests.rs b/pallets/dapp-staking-v3/src/test/tests.rs index 7f6f3d390b..1a53113ad6 100644 --- a/pallets/dapp-staking-v3/src/test/tests.rs +++ b/pallets/dapp-staking-v3/src/test/tests.rs @@ -1260,9 +1260,6 @@ fn unstake_with_unclaimed_rewards_fails() { DappStaking::unstake(RuntimeOrigin::signed(account), smart_contract, 1), Error::::UnclaimedRewards ); - - // Advance to the next period, unstake should still fail. - advance_to_next_period(); }) }