Skip to content

Commit

Permalink
Tier param setting call (#1421)
Browse files Browse the repository at this point in the history
* Tier param setting call

* Cleanup & benchmarks

* REmove todo

* Add event

* Review comments

* Update migration

* Fix

* Fix comment

* Weights updates
  • Loading branch information
Dinonard authored Feb 19, 2025
1 parent ff28544 commit 8b238f8
Show file tree
Hide file tree
Showing 18 changed files with 1,226 additions and 918 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Usage
/bench astar-dev pallet_balances
# benchmark multiple pallets
/bench astar-dev pallet_balances,pallet_dapps_staking
/bench astar-dev pallet_balances,pallet_dapp_staking
# benchmark all pallets
/bench astar-dev all
# benchmark multiple runtimes with multiple pallets
/bench astar-dev,shibuya-dev pallet_balances,pallet_dapps_staking
/bench astar-dev,shibuya-dev pallet_balances,pallet_dapp_staking
```


Expand Down
22 changes: 22 additions & 0 deletions pallets/dapp-staking/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,28 @@ mod benchmarks {
);
}

#[benchmark]
fn set_static_tier_params() {
initial_config::<T>();

let mut tier_params = StaticTierParams::<T>::get();
assert!(tier_params.is_valid(), "Sanity check");

// Modify them so they aren't the same anymore
tier_params.reward_portion[0] = Permill::zero();

#[extrinsic_call]
_(RawOrigin::Root, tier_params.clone());

assert_eq!(StaticTierParams::<T>::get(), tier_params);
assert_last_event::<T>(
Event::<T>::NewTierParameters {
params: tier_params,
}
.into(),
);
}

/// TODO: remove this benchmark once BonusStatus update is done
#[benchmark]
fn update_bonus_step_success() {
Expand Down
3 changes: 2 additions & 1 deletion pallets/dapp-staking/src/benchmarking/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use super::{Pallet as DappStaking, *};

use astar_primitives::Balance;
use astar_primitives::{dapp_staking::STANDARD_TIER_SLOTS_ARGS, Balance};

use frame_system::Pallet as System;

Expand Down Expand Up @@ -194,6 +194,7 @@ pub(super) fn init_tier_settings<T: Config>() {
},
])
.unwrap(),
slot_number_args: STANDARD_TIER_SLOTS_ARGS,
};

let total_issuance = 1000 * MIN_TIER_THRESHOLD;
Expand Down
41 changes: 37 additions & 4 deletions pallets/dapp-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use astar_primitives::{
dapp_staking::{
AccountCheck, CycleConfiguration, DAppId, EraNumber, Observer as DAppStakingObserver,
PeriodNumber, Rank, RankedTier, SmartContractHandle, StakingRewardHandler, TierId,
TierSlots as TierSlotFunc,
TierSlots as TierSlotFunc, STANDARD_TIER_SLOTS_ARGS,
},
oracle::PriceProvider,
Balance, BlockNumber,
Expand Down Expand Up @@ -330,6 +330,10 @@ pub mod pallet {
destination_contract: T::SmartContract,
amount: Balance,
},
/// Tier parameters, used to calculate tier configuration, have been updated, and will be applicable from next era.
NewTierParameters {
params: TierParameters<T::NumberOfTiers>,
},
}

#[pallet::error]
Expand Down Expand Up @@ -406,6 +410,8 @@ pub mod pallet {
NoExpiredEntries,
/// Force call is not allowed in production.
ForceNotAllowed,
/// Invalid tier parameters were provided. This can happen if any number exceeds 100% or if number of elements does not match the number of tiers.
InvalidTierParams,
/// Same contract specified as source and destination.
SameContracts,
}
Expand Down Expand Up @@ -523,10 +529,11 @@ pub mod pallet {
StorageValue<_, BonusUpdateStateFor<T>, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig<T> {
pub struct GenesisConfig<T: Config> {
pub reward_portion: Vec<Permill>,
pub slot_distribution: Vec<Permill>,
pub tier_thresholds: Vec<TierThreshold>,
pub slot_number_args: (u64, u64),
pub slots_per_tier: Vec<u16>,
pub safeguard: Option<bool>,
#[serde(skip)]
Expand All @@ -546,6 +553,7 @@ pub mod pallet {
required_percentage: Perbill::from_percent(i),
})
.collect(),
slot_number_args: STANDARD_TIER_SLOTS_ARGS,
slots_per_tier: vec![100; num_tiers as usize],
safeguard: None,
_config: Default::default(),
Expand All @@ -570,6 +578,7 @@ pub mod pallet {
self.tier_thresholds.clone(),
)
.expect("Invalid number of tier thresholds provided."),
slot_number_args: self.slot_number_args,
};
assert!(
tier_params.is_valid(),
Expand Down Expand Up @@ -1399,6 +1408,28 @@ pub mod pallet {
.into())
}

/// Used to set static tier parameters, which are used to calculate tier configuration.
/// Tier configuration defines tier entry threshold values, number of slots, and reward portions.
///
/// This is a delicate call and great care should be taken when changing these
/// values since it has a significant impact on the reward system.
#[pallet::call_index(22)]
#[pallet::weight(T::WeightInfo::set_static_tier_params())]
pub fn set_static_tier_params(
origin: OriginFor<T>,
params: TierParameters<T::NumberOfTiers>,
) -> DispatchResult {
Self::ensure_pallet_enabled()?;
ensure_root(origin)?;
ensure!(params.is_valid(), Error::<T>::InvalidTierParams);

StaticTierParams::<T>::set(params.clone());

Self::deposit_event(Event::<T>::NewTierParameters { params });

Ok(())
}

/// Active update `BonusStatus` according to the new MaxBonusSafeMovesPerPeriod from config
/// for all already existing StakerInfo in steps, consuming up to the specified amount of
/// weight.
Expand All @@ -1407,7 +1438,7 @@ pub mod pallet {
/// In any case the weight_limit is clamped between the minimum & maximum allowed values.
///
/// TODO: remove this extrinsic once BonusStatus update is done
#[pallet::call_index(22)]
#[pallet::call_index(200)]
#[pallet::weight({
Pallet::<T>::clamp_call_weight(*weight_limit)
})]
Expand Down Expand Up @@ -2773,7 +2804,9 @@ pub mod pallet {
let new_staking_info = SingularStakingInfo {
previous_staked: staking_info.previous_staked,
staked: staking_info.staked,
bonus_status: *BonusStatusWrapperFor::<T>::default(),
bonus_status: staking_info
.bonus_status
.saturating_add(T::MaxBonusSafeMovesPerPeriod::get()),
};

StakerInfo::<T>::insert(&account, &smart_contract, new_staking_info);
Expand Down
77 changes: 69 additions & 8 deletions pallets/dapp-staking/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,33 +54,82 @@ pub mod versioned_migrations {
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;

/// Migration V8 to V9 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring
/// the migration is only performed when on-chain version is 9.
pub type V8ToV9<T> = frame_support::migrations::VersionedMigration<
pub type V8ToV9<T, InitArgs> = frame_support::migrations::VersionedMigration<
8,
9,
v9::ActiveUpdateBonusStatus<T>,
v9::VersionMigrateV8ToV9<T, InitArgs>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;
}

mod v9 {
use super::*;
use frame_support::DefaultNoBound;

#[derive(
Encode,
Decode,
MaxEncodedLen,
RuntimeDebugNoBound,
PartialEqNoBound,
DefaultNoBound,
EqNoBound,
CloneNoBound,
TypeInfo,
)]
#[scale_info(skip_type_params(NT))]
pub struct TierParametersV8<NT: Get<u32>> {
/// Reward distribution per tier, in percentage.
/// First entry refers to the first tier, and so on.
/// The sum of all values must not exceed 100%.
/// In case it is less, portion of rewards will never be distributed.
pub(crate) reward_portion: BoundedVec<Permill, NT>,
/// Distribution of number of slots per tier, in percentage.
/// First entry refers to the first tier, and so on.
/// The sum of all values must not exceed 100%.
/// In case it is less, slot capacity will never be fully filled.
pub(crate) slot_distribution: BoundedVec<Permill, NT>,
/// Requirements for entry into each tier.
/// First entry refers to the first tier, and so on.
pub(crate) tier_thresholds: BoundedVec<TierThreshold, NT>,
}

// The loyal staker flag is updated to `u8` with the new MaxBonusSafeMovesPerPeriod from config
// for all already existing StakerInfo.
pub struct ActiveUpdateBonusStatus<T>(PhantomData<T>);
pub struct VersionMigrateV8ToV9<T, InitArgs>(PhantomData<(T, InitArgs)>);

impl<T: Config> UncheckedOnRuntimeUpgrade for ActiveUpdateBonusStatus<T> {
impl<T: Config, InitArgs: Get<(u64, u64)>> UncheckedOnRuntimeUpgrade
for VersionMigrateV8ToV9<T, InitArgs>
{
fn on_runtime_upgrade() -> Weight {
// When upgrade happens, we need to put dApp staking v3 into maintenance mode immediately.
let mut consumed_weight = T::DbWeight::get().reads_writes(1, 2);
let mut consumed_weight = T::DbWeight::get().reads_writes(2, 3);

// When upgrade happens, we need to put dApp staking into maintenance mode immediately.
ActiveProtocolState::<T>::mutate(|state| {
state.maintenance = true;
});
log::info!("Maintenance mode enabled.");

// Result is ignored - upgrade must succeed, there's no fallback in case it doesn't.
let _ignore = StaticTierParams::<T>::translate::<TierParametersV8<T::NumberOfTiers>, _>(
|maybe_old_params| match maybe_old_params {
Some(old_params) => Some(TierParameters {
slot_distribution: old_params.slot_distribution,
reward_portion: old_params.reward_portion,
tier_thresholds: old_params.tier_thresholds,
slot_number_args: InitArgs::get(),
}),
_ => {
log::error!("Failed to translate StaticTierParams from previous V8 type to current V9 type.");
None
}
},
);

// In case of try-runtime, we want to execute the whole logic, to ensure it works
// with on-chain data.
if cfg!(feature = "try-runtime") {
Expand Down Expand Up @@ -126,24 +175,35 @@ mod v9 {

#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
ensure!(
assert!(
Pallet::<T>::on_chain_storage_version() >= 9,
"dapp-staking::migration::v9: wrong storage version"
);

assert!(
!ActiveProtocolState::<T>::get().maintenance,
"Maintenance mode must be disabled after the successful runtime upgrade."
);

let new_default_bonus_status = *crate::types::BonusStatusWrapperFor::<T>::default();
for (_, _, staking_info) in StakerInfo::<T>::iter() {
assert_eq!(staking_info.bonus_status, new_default_bonus_status);
assert!(
staking_info.bonus_status >= new_default_bonus_status.saturating_sub(1)
&& staking_info.bonus_status <= new_default_bonus_status
);
}
log::info!(
target: LOG_TARGET,
"All entries updated to new_default_bonus_status {}", new_default_bonus_status,
);

let new_tier_params = StaticTierParams::<T>::get();
assert!(
new_tier_params.is_valid(),
"New tier params are invalid, re-check the values!"
);
assert_eq!(new_tier_params.slot_number_args, InitArgs::get());

Ok(())
}
}
Expand Down Expand Up @@ -206,6 +266,7 @@ pub mod v8 {
slot_distribution: old_params.slot_distribution,
reward_portion: old_params.reward_portion,
tier_thresholds,
slot_number_args: Default::default(),
}),
Err(err) => {
log::error!(
Expand Down
5 changes: 4 additions & 1 deletion pallets/dapp-staking/src/test/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ use sp_runtime::{BuildStorage, Permill};
use sp_std::cell::RefCell;

use astar_primitives::{
dapp_staking::{Observer as DappStakingObserver, SmartContract, StandardTierSlots},
dapp_staking::{
Observer as DappStakingObserver, SmartContract, StandardTierSlots, STANDARD_TIER_SLOTS_ARGS,
},
Balance, BlockNumber,
};
use frame_system::{EnsureRoot, EnsureSignedBy};
Expand Down Expand Up @@ -333,6 +335,7 @@ impl ExtBuilder {
},
])
.unwrap(),
slot_number_args: STANDARD_TIER_SLOTS_ARGS,
};

let total_issuance = <Test as Config>::Currency::total_issuance();
Expand Down
Loading

0 comments on commit 8b238f8

Please sign in to comment.