Skip to content

Commit a52c2fd

Browse files
authored
Feat: Inflation decay factor (#1536)
* feat: inflation decay factor * decay factor rework * fmt * weights updated * Revert "fmt" This reverts commit ba281d9. * Revert "decay factor rework" This reverts commit f71c41d. * init CycleMaxEmission * some assert cleanups in tests * readjust config in force_set_decay_rate * fmt * split config decay and block reward payouts * decay factor in config * fmt * small adjustments and weights * tweak benchmark params * remove force_set_decay_factor * weights and assert updated * integration test + benchmark correct genesis * weights updated
1 parent 24f980c commit a52c2fd

File tree

16 files changed

+905
-358
lines changed

16 files changed

+905
-358
lines changed

pallets/inflation/src/benchmarking.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ fn initial_config<T: Config>() {
4242
adjustable_stakers_part: Perquintill::from_percent(35),
4343
bonus_part: Perquintill::from_percent(12),
4444
ideal_staking_rate: Perquintill::from_percent(50),
45+
decay_rate: Perquintill::from_percent(99),
4546
};
4647
assert!(params.is_valid());
4748

@@ -59,6 +60,8 @@ fn initial_config<T: Config>() {
5960
adjustable_staker_reward_pool_per_era: 99999 * UNIT,
6061
bonus_reward_pool_per_period: 123987 * UNIT,
6162
ideal_staking_rate: Perquintill::from_percent(50),
63+
decay_rate: Perquintill::from_percent(99),
64+
decay_factor: Perquintill::one(),
6265
};
6366

6467
InflationParams::<T>::put(params);
@@ -144,7 +147,9 @@ mod benchmarks {
144147
Pallet::<T>::on_finalize(block);
145148
}
146149

147-
assert_eq!(ActiveInflationConfig::<T>::get(), init_config);
150+
let mut expected_config = init_config.clone();
151+
expected_config.decay_factor = init_config.decay_factor * init_config.decay_rate;
152+
assert_eq!(ActiveInflationConfig::<T>::get(), expected_config);
148153

149154
// The 'sane' assumption is that at least something will be issued for treasury & collators
150155
assert!(T::Currency::total_issuance() > init_issuance);

pallets/inflation/src/lib.rs

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ pub mod pallet {
137137
use super::*;
138138

139139
/// The current storage version.
140-
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
140+
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
141141

142142
#[pallet::pallet]
143143
#[pallet::storage_version(STORAGE_VERSION)]
@@ -211,7 +211,8 @@ pub mod pallet {
211211
assert!(self.params.is_valid());
212212

213213
let starting_era = 1;
214-
let config = Pallet::<T>::recalculate_inflation(starting_era);
214+
let starting_decay_factor = Perquintill::one();
215+
let config = Pallet::<T>::recalculate_inflation(starting_era, starting_decay_factor);
215216

216217
ActiveInflationConfig::<T>::put(config);
217218
InflationParams::<T>::put(self.params);
@@ -221,13 +222,22 @@ pub mod pallet {
221222
#[pallet::hooks]
222223
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
223224
fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
224-
Self::payout_block_rewards();
225+
let mut weight = T::DbWeight::get().reads(1);
226+
let mut config = ActiveInflationConfig::<T>::get();
227+
228+
if config.decay_rate != Perquintill::one() {
229+
config.decay_factor = config.decay_factor * config.decay_rate;
230+
ActiveInflationConfig::<T>::put(config);
231+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
232+
}
233+
234+
Self::payout_block_rewards(&config);
225235

226236
// Benchmarks won't account for the whitelisted storage access so this needs to be added manually.
227-
//
228-
// ActiveInflationConfig - 1 DB read
229237
// DoRecalculation - 1 DB read
230-
<T as frame_system::Config>::DbWeight::get().reads(2)
238+
weight = weight.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(1));
239+
240+
weight
231241
}
232242

233243
fn on_finalize(_now: BlockNumberFor<T>) {
@@ -238,7 +248,8 @@ pub mod pallet {
238248
//
239249
// This should be done as late as possible, to ensure all operations that modify issuance are done.
240250
if let Some(next_era) = DoRecalculation::<T>::get() {
241-
let config = Self::recalculate_inflation(next_era);
251+
let decay_factor = ActiveInflationConfig::<T>::get().decay_factor;
252+
let config = Self::recalculate_inflation(next_era, decay_factor);
242253
ActiveInflationConfig::<T>::put(config.clone());
243254
DoRecalculation::<T>::kill();
244255

@@ -294,8 +305,8 @@ pub mod pallet {
294305
) -> DispatchResult {
295306
ensure_root(origin)?;
296307

297-
let config = Self::recalculate_inflation(next_era);
298-
308+
let decay_factor = ActiveInflationConfig::<T>::get().decay_factor;
309+
let config = Self::recalculate_inflation(next_era, decay_factor);
299310
ActiveInflationConfig::<T>::put(config.clone());
300311

301312
Self::deposit_event(Event::<T>::ForcedInflationRecalculation { config });
@@ -331,25 +342,25 @@ pub mod pallet {
331342
}
332343

333344
impl<T: Config> Pallet<T> {
334-
/// Payout block rewards to the beneficiaries.
335-
///
336-
/// Return the total amount issued.
337-
fn payout_block_rewards() -> Balance {
338-
let config = ActiveInflationConfig::<T>::get();
345+
/// Payout block rewards to the beneficiaries applying the decay factor.
346+
fn payout_block_rewards(config: &InflationConfiguration) {
347+
let collator_rewards = config.decay_factor * config.collator_reward_per_block;
348+
let treasury_rewards = config.decay_factor * config.treasury_reward_per_block;
339349

340-
let collator_amount = T::Currency::issue(config.collator_reward_per_block);
341-
let treasury_amount = T::Currency::issue(config.treasury_reward_per_block);
350+
let collator_amount = T::Currency::issue(collator_rewards);
351+
let treasury_amount = T::Currency::issue(treasury_rewards);
342352

343353
T::PayoutPerBlock::collators(collator_amount);
344354
T::PayoutPerBlock::treasury(treasury_amount);
345-
346-
config.collator_reward_per_block + config.treasury_reward_per_block
347355
}
348356

349357
/// Recalculates the inflation based on the current total issuance & inflation parameters.
350358
///
351359
/// Returns the new inflation configuration.
352-
pub(crate) fn recalculate_inflation(next_era: EraNumber) -> InflationConfiguration {
360+
pub(crate) fn recalculate_inflation(
361+
next_era: EraNumber,
362+
decay_factor: Perquintill,
363+
) -> InflationConfiguration {
353364
// Calculate max emission based on the current total issuance.
354365
let params = InflationParams::<T>::get();
355366
let total_issuance = T::Currency::total_issuance();
@@ -358,7 +369,7 @@ pub mod pallet {
358369
let recalculation_era =
359370
next_era.saturating_add(T::CycleConfiguration::eras_per_cycle());
360371

361-
Self::new_config(recalculation_era, max_emission)
372+
Self::new_config(recalculation_era, max_emission, decay_factor)
362373
}
363374

364375
/// Re-adjust the existing inflation configuration using the current inflation parameters.
@@ -411,13 +422,14 @@ pub mod pallet {
411422
.saturating_add(bonus_reward_pool);
412423

413424
// 4. Calculate new inflation configuration
414-
Self::new_config(config.recalculation_era, max_emission)
425+
Self::new_config(config.recalculation_era, max_emission, config.decay_factor)
415426
}
416427

417428
// Calculate new inflation configuration, based on the provided `max_emission`.
418429
fn new_config(
419430
recalculation_era: EraNumber,
420431
max_emission: Balance,
432+
decay_factor: Perquintill,
421433
) -> InflationConfiguration {
422434
let params = InflationParams::<T>::get();
423435

@@ -478,6 +490,8 @@ pub mod pallet {
478490
adjustable_staker_reward_pool_per_era,
479491
bonus_reward_pool_per_period,
480492
ideal_staking_rate: params.ideal_staking_rate,
493+
decay_rate: params.decay_rate,
494+
decay_factor,
481495
};
482496
new_inflation_config.sanity_check();
483497

@@ -512,15 +526,18 @@ pub mod pallet {
512526
let adjustment_factor = staked_ratio / config.ideal_staking_rate;
513527

514528
let adjustable_part = adjustment_factor * config.adjustable_staker_reward_pool_per_era;
515-
let staker_reward_pool = config
516-
.base_staker_reward_pool_per_era
517-
.saturating_add(adjustable_part);
529+
let staker_reward_pool = config.decay_factor
530+
* config
531+
.base_staker_reward_pool_per_era
532+
.saturating_add(adjustable_part);
533+
let dapp_reward_pool = config.decay_factor * config.dapp_reward_pool_per_era;
518534

519-
(staker_reward_pool, config.dapp_reward_pool_per_era)
535+
(staker_reward_pool, dapp_reward_pool)
520536
}
521537

522538
fn bonus_reward_pool() -> Balance {
523-
ActiveInflationConfig::<T>::get().bonus_reward_pool_per_period
539+
let config = ActiveInflationConfig::<T>::get();
540+
config.decay_factor * config.bonus_reward_pool_per_period
524541
}
525542

526543
fn payout_reward(account: &T::AccountId, reward: Balance) -> Result<(), ()> {
@@ -571,6 +588,14 @@ pub struct InflationConfiguration {
571588
/// Used to derive exact amount of adjustable staker rewards.
572589
#[codec(compact)]
573590
pub ideal_staking_rate: Perquintill,
591+
/// Per-block decay rate applied to the decay factor.
592+
/// A value of `Perquintill::one()` means no decay.
593+
#[codec(compact)]
594+
pub decay_rate: Perquintill,
595+
/// Compounded decay multiplied into rewards when they are actually paid.
596+
/// A value of `Perquintill::one()` means no decay.
597+
#[codec(compact)]
598+
pub decay_factor: Perquintill,
574599
}
575600

576601
impl InflationConfiguration {
@@ -643,6 +668,10 @@ pub struct InflationParameters {
643668
/// Used to derive exact amount of adjustable staker rewards.
644669
#[codec(compact)]
645670
pub ideal_staking_rate: Perquintill,
671+
/// Per-block decay rate applied to all reward pools and per-block rewards.
672+
/// A value of `Perquintill::one()` means no decay.
673+
#[codec(compact)]
674+
pub decay_rate: Perquintill,
646675
}
647676

648677
impl InflationParameters {
@@ -682,6 +711,13 @@ impl Default for InflationParameters {
682711
adjustable_stakers_part: Perquintill::from_percent(35),
683712
bonus_part: Perquintill::from_percent(12),
684713
ideal_staking_rate: Perquintill::from_percent(50),
714+
715+
// Use non-default decay rate when benchmarking to measure decay calculation
716+
#[cfg(feature = "runtime-benchmarks")]
717+
decay_rate: Perquintill::from_percent(99),
718+
719+
#[cfg(not(feature = "runtime-benchmarks"))]
720+
decay_rate: Perquintill::one(),
685721
}
686722
}
687723
}

0 commit comments

Comments
 (0)