From 4ea8556c37531853f921d329cbe98fedb6f1c842 Mon Sep 17 00:00:00 2001 From: Dino Pacandi Date: Wed, 25 Oct 2023 16:11:02 +0200 Subject: [PATCH] Genesis config --- Cargo.lock | 1 + bin/collator/Cargo.toml | 1 + bin/collator/src/local/chain_spec.rs | 40 ++++++++++-- pallets/dapp-staking-v3/src/lib.rs | 77 ++++++++++++++++++++-- pallets/dapp-staking-v3/src/test/mock.rs | 8 ++- pallets/dapp-staking-v3/src/types.rs | 81 +++++++++++++++++++++--- 6 files changed, 187 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19c286fc40..ab6f066763 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -448,6 +448,7 @@ dependencies = [ "moonbeam-rpc-trace", "moonbeam-rpc-txpool", "pallet-block-reward", + "pallet-dapp-staking-v3", "pallet-ethereum", "pallet-evm", "pallet-transaction-payment", diff --git a/bin/collator/Cargo.toml b/bin/collator/Cargo.toml index 3c7fccb18e..d8f46e7b2a 100644 --- a/bin/collator/Cargo.toml +++ b/bin/collator/Cargo.toml @@ -95,6 +95,7 @@ shiden-runtime = { workspace = true, features = ["std"] } # astar pallets dependencies astar-primitives = { workspace = true } pallet-block-reward = { workspace = true } +pallet-dapp-staking-v3 = { workspace = true } # frame dependencies frame-system = { workspace = true, features = ["std"] } diff --git a/bin/collator/src/local/chain_spec.rs b/bin/collator/src/local/chain_spec.rs index 8d56c8747c..4774784754 100644 --- a/bin/collator/src/local/chain_spec.rs +++ b/bin/collator/src/local/chain_spec.rs @@ -20,17 +20,19 @@ use local_runtime::{ wasm_binary_unwrap, AccountId, AuraConfig, AuraId, BalancesConfig, BaseFeeConfig, - BlockRewardConfig, CouncilConfig, DemocracyConfig, EVMConfig, GenesisConfig, GrandpaConfig, - GrandpaId, Precompiles, Signature, SudoConfig, SystemConfig, TechnicalCommitteeConfig, - TreasuryConfig, VestingConfig, + BlockRewardConfig, CouncilConfig, DappStakingConfig, DemocracyConfig, EVMConfig, GenesisConfig, + GrandpaConfig, GrandpaId, Precompiles, Signature, SudoConfig, SystemConfig, + TechnicalCommitteeConfig, TreasuryConfig, VestingConfig, }; use sc_service::ChainType; use sp_core::{crypto::Ss58Codec, sr25519, Pair, Public}; use sp_runtime::{ traits::{IdentifyAccount, Verify}, - Perbill, + Perbill, Permill, }; +use pallet_dapp_staking_v3::TierThreshold; + type AccountPublic = ::Signer; /// Specialized `ChainSpec` for Shiden Network. @@ -181,6 +183,36 @@ fn testnet_genesis( }, democracy: DemocracyConfig::default(), treasury: TreasuryConfig::default(), + dapp_staking: DappStakingConfig { + reward_portion: vec![ + Permill::from_percent(40), + Permill::from_percent(30), + Permill::from_percent(20), + Permill::from_percent(10), + ], + slot_distribution: vec![ + Permill::from_percent(10), + Permill::from_percent(20), + Permill::from_percent(30), + Permill::from_percent(40), + ], + tier_thresholds: vec![ + TierThreshold::DynamicTvlAmount { + amount: 100, + minimum_amount: 80, + }, + TierThreshold::DynamicTvlAmount { + amount: 50, + minimum_amount: 40, + }, + TierThreshold::DynamicTvlAmount { + amount: 20, + minimum_amount: 20, + }, + TierThreshold::FixedTvlAmount { amount: 10 }, + ], + slots_per_tier: vec![10, 20, 30, 40], + }, } } diff --git a/pallets/dapp-staking-v3/src/lib.rs b/pallets/dapp-staking-v3/src/lib.rs index 2bfcb74ace..823266f26b 100644 --- a/pallets/dapp-staking-v3/src/lib.rs +++ b/pallets/dapp-staking-v3/src/lib.rs @@ -48,21 +48,19 @@ use frame_support::{ use frame_system::pallet_prelude::*; use sp_runtime::{ traits::{BadOrigin, Saturating, Zero}, - Perbill, + Perbill, Permill, }; pub use sp_std::vec::Vec; use astar_primitives::Balance; -use crate::types::*; -pub use crate::types::{PriceProvider, RewardPoolProvider}; - pub use pallet::*; #[cfg(test)] mod test; mod types; +pub use types::*; // TODO: maybe make it more restrictive later const STAKING_ID: LockIdentifier = *b"dapstake"; @@ -401,6 +399,77 @@ pub mod pallet { pub type DAppTiers = StorageMap<_, Twox64Concat, EraNumber, DAppTierRewardsFor, OptionQuery>; + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + pub reward_portion: Vec, + pub slot_distribution: Vec, + pub tier_thresholds: Vec, + pub slots_per_tier: Vec, + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + // Prepare tier parameters & verify their correctness + let tier_params = TierParameters:: { + reward_portion: BoundedVec::::try_from( + self.reward_portion.clone(), + ) + .expect("Invalid number of reward portions provided."), + slot_distribution: BoundedVec::::try_from( + self.slot_distribution.clone(), + ) + .expect("Invalid number of slot distributions provided."), + tier_thresholds: BoundedVec::::try_from( + self.tier_thresholds.clone(), + ) + .expect("Invalid number of tier thresholds provided."), + }; + assert!( + tier_params.is_valid(), + "Invalid tier parameters values provided." + ); + + // Prepare tier configuration and verify its correctness + let number_of_slots = self + .slots_per_tier + .iter() + .fold(0, |acc, &slots| acc + slots); + let tier_config = TiersConfiguration:: { + number_of_slots, + slots_per_tier: BoundedVec::::try_from( + self.slots_per_tier.clone(), + ) + .expect("Invalid number of slots per tier entries provided."), + reward_portion: tier_params.reward_portion.clone(), + tier_thresholds: tier_params.tier_thresholds.clone(), + }; + assert!( + tier_params.is_valid(), + "Invalid tier config values provided." + ); + + // Prepare initial protocol state + let protocol_state = ProtocolState { + era: 1, + next_era_start: Pallet::::blocks_per_voting_period() + 1_u32.into(), + period_info: PeriodInfo { + number: 1, + period_type: PeriodType::Voting, + ending_era: 2, + }, + maintenance: false, + }; + + // Initialize necessary storage items + ActiveProtocolState::::put(protocol_state); + StaticTierParams::::put(tier_params); + TierConfig::::put(tier_config.clone()); + NextTierConfig::::put(tier_config); + } + } + #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(now: BlockNumberFor) -> Weight { diff --git a/pallets/dapp-staking-v3/src/test/mock.rs b/pallets/dapp-staking-v3/src/test/mock.rs index e788349707..6b05742d93 100644 --- a/pallets/dapp-staking-v3/src/test/mock.rs +++ b/pallets/dapp-staking-v3/src/test/mock.rs @@ -180,14 +180,14 @@ impl ExtBuilder { ext.execute_with(|| { System::set_block_number(1); - // TODO: not sure why the mess with type happens here, I can check it later + // 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 = <::StandardErasPerVotingPeriod as sp_core::Get<_>>::get( ); - // TODO: handle this via GenesisConfig, and some helper functions to set the state + // Init protocol state pallet_dapp_staking::ActiveProtocolState::::put(ProtocolState { era: 1, next_era_start: era_length.saturating_mul(voting_period_length_in_eras.into()) + 1, @@ -199,7 +199,7 @@ impl ExtBuilder { maintenance: false, }); - // TODO: improve this later, should be handled via genesis? + // Init tier params let tier_params = TierParameters::<::NumberOfTiers> { reward_portion: BoundedVec::try_from(vec![ Permill::from_percent(40), @@ -223,6 +223,8 @@ impl ExtBuilder { ]) .unwrap(), }; + + // Init tier config, based on the initial params let init_tier_config = TiersConfiguration::<::NumberOfTiers> { number_of_slots: 100, slots_per_tier: BoundedVec::try_from(vec![10, 20, 30, 40]).unwrap(), diff --git a/pallets/dapp-staking-v3/src/types.rs b/pallets/dapp-staking-v3/src/types.rs index 834cb6ea34..08320b29e6 100644 --- a/pallets/dapp-staking-v3/src/types.rs +++ b/pallets/dapp-staking-v3/src/types.rs @@ -26,7 +26,7 @@ use sp_runtime::{ traits::{AtLeast32BitUnsigned, UniqueSaturatedInto, Zero}, FixedPointNumber, Permill, Saturating, }; -pub use sp_std::vec::Vec; +pub use sp_std::{fmt::Debug, vec::Vec}; use astar_primitives::Balance; @@ -281,10 +281,19 @@ where } /// General info about user's stakes -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, +)] #[scale_info(skip_type_params(UnlockingLen))] pub struct AccountLedger< - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy, + BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, UnlockingLen: Get, > { /// How much active locked amount an account has. @@ -307,7 +316,7 @@ pub struct AccountLedger< impl Default for AccountLedger where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy, + BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, UnlockingLen: Get, { fn default() -> Self { @@ -323,7 +332,7 @@ where impl AccountLedger where - BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy, + BlockNumber: AtLeast32BitUnsigned + MaxEncodedLen + Copy + Debug, UnlockingLen: Get, { /// Empty if no locked/unlocking/staked info exists. @@ -1006,7 +1015,17 @@ impl SingularStakingInfo { const STAKING_SERIES_HISTORY: u32 = 3; /// Composite type that holds information about how much was staked on a contract during some past eras & periods, including the current era & period. -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, + Default, +)] pub struct ContractStakeAmountSeries(BoundedVec>); impl ContractStakeAmountSeries { /// Helper function to create a new instance of `ContractStakeAmountSeries`. @@ -1246,7 +1265,16 @@ pub enum EraRewardSpanError { } /// Used to efficiently store era span information. -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, +)] #[scale_info(skip_type_params(SL))] pub struct EraRewardSpan> { /// Span of EraRewardInfo entries. @@ -1333,6 +1361,7 @@ where /// Description of tier entry requirement. #[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum TierThreshold { /// Entry into tier is mandated by minimum amount of staked funds. /// Value is fixed, and is not expected to change in between periods. @@ -1357,7 +1386,16 @@ impl TierThreshold { } /// Top level description of tier slot parameters used to calculate tier configuration. -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, +)] #[scale_info(skip_type_params(NT))] pub struct TierParameters> { /// Reward distribution per tier, in percentage. @@ -1381,6 +1419,8 @@ impl> TierParameters { number_of_tiers == self.reward_portion.len() && number_of_tiers == self.slot_distribution.len() && number_of_tiers == self.tier_thresholds.len() + + // TODO: Make check more detailed, verify that entries sum up to 1 or 100% } } @@ -1397,7 +1437,16 @@ impl> Default for TierParameters { // TODO: refactor these structs so we only have 1 bounded vector, where each entry contains all the necessary info to describe the tier? /// Configuration of dApp tiers. -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, +)] #[scale_info(skip_type_params(NT))] pub struct TiersConfiguration> { /// Total number of slots. @@ -1553,7 +1602,16 @@ pub struct DAppTier { } /// Information about all of the dApps that got into tiers, and tier rewards -#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +#[derive( + Encode, + Decode, + MaxEncodedLen, + RuntimeDebugNoBound, + PartialEqNoBound, + EqNoBound, + CloneNoBound, + TypeInfo, +)] #[scale_info(skip_type_params(MD, NT))] pub struct DAppTierRewards, NT: Get> { /// DApps and their corresponding tiers (or `None` if they have been claimed in the meantime) @@ -1651,6 +1709,9 @@ pub trait PriceProvider { 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. ///