Skip to content

Commit

Permalink
feat: introduce pallet-parameters to Westend to parameterize inflation (
Browse files Browse the repository at this point in the history
#4938)

Fixes #4907

## Changes
- Add `pallet-parameters` to Westend runtime
- Add `relay_era_payout` function to Polkadot runtime common + deprecate
previous `era_payout` function
- Add unit tests for `relay_era_payout`, matching previous unit tests
for `era_payout`
- Remove `pallet_staking_reward_curve` in Westend runtime
- Add `dynamic_params` to replace constants used for
`pallet_staking_reward_curve`

Polkadot address: 5DybbVdLvVWd7MiA1YwkzLUNL1ThMDicozbuLc8v9pQEScPQ

---------

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: kianenigma <kian@parity.io>
Co-authored-by: command-bot <>
  • Loading branch information
3 people authored Jul 22, 2024
1 parent 2095689 commit 6e520eb
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

194 changes: 171 additions & 23 deletions polkadot/runtime/common/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,29 +67,51 @@ where
}
}

pub fn era_payout(
total_staked: Balance,
total_stakable: Balance,
max_annual_inflation: Perquintill,
period_fraction: Perquintill,
auctioned_slots: u64,
) -> (Balance, Balance) {
use pallet_staking_reward_fn::compute_inflation;
/// Parameters passed into [`relay_era_payout`] function.
pub struct EraPayoutParams {
/// Total staked amount.
pub total_staked: Balance,
/// Total stakable amount.
///
/// Usually, this is equal to the total issuance, except if a large part of the issuance is
/// locked in another sub-system.
pub total_stakable: Balance,
/// Ideal stake ratio, which is deducted by `legacy_auction_proportion` if not `None`.
pub ideal_stake: Perquintill,
/// Maximum inflation rate.
pub max_annual_inflation: Perquintill,
/// Minimum inflation rate.
pub min_annual_inflation: Perquintill,
/// Falloff used to calculate era payouts.
pub falloff: Perquintill,
/// Fraction of the era period used to calculate era payouts.
pub period_fraction: Perquintill,
/// Legacy auction proportion, which substracts from `ideal_stake` if not `None`.
pub legacy_auction_proportion: Option<Perquintill>,
}

/// A specialized function to compute the inflation of the staking system, tailored for polkadot
/// relay chains, such as Polkadot, Kusama and Westend.
pub fn relay_era_payout(params: EraPayoutParams) -> (Balance, Balance) {
use sp_runtime::traits::Saturating;

let min_annual_inflation = Perquintill::from_rational(25u64, 1000u64);
let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation);
let EraPayoutParams {
total_staked,
total_stakable,
ideal_stake,
max_annual_inflation,
min_annual_inflation,
falloff,
period_fraction,
legacy_auction_proportion,
} = params;

// 30% reserved for up to 60 slots.
let auction_proportion = Perquintill::from_rational(auctioned_slots.min(60), 200u64);
let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation);

// Therefore the ideal amount at stake (as a percentage of total issuance) is 75% less the
// amount that we expect to be taken up with auctions.
let ideal_stake = Perquintill::from_percent(75).saturating_sub(auction_proportion);
let ideal_stake = ideal_stake.saturating_sub(legacy_auction_proportion.unwrap_or_default());

let stake = Perquintill::from_rational(total_staked, total_stakable);
let falloff = Perquintill::from_percent(5);
let adjustment = compute_inflation(stake, ideal_stake, falloff);
let adjustment = pallet_staking_reward_fn::compute_inflation(stake, ideal_stake, falloff);
let staking_inflation =
min_annual_inflation.saturating_add(delta_annual_inflation * adjustment);

Expand Down Expand Up @@ -371,6 +393,46 @@ mod tests {
t.into()
}

pub fn deprecated_era_payout(
total_staked: Balance,
total_stakable: Balance,
max_annual_inflation: Perquintill,
period_fraction: Perquintill,
auctioned_slots: u64,
) -> (Balance, Balance) {
use pallet_staking_reward_fn::compute_inflation;
use sp_runtime::traits::Saturating;

let min_annual_inflation = Perquintill::from_rational(25u64, 1000u64);
let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation);

// 30% reserved for up to 60 slots.
let auction_proportion = Perquintill::from_rational(auctioned_slots.min(60), 200u64);

// Therefore the ideal amount at stake (as a percentage of total issuance) is 75% less the
// amount that we expect to be taken up with auctions.
let ideal_stake = Perquintill::from_percent(75).saturating_sub(auction_proportion);

let stake = Perquintill::from_rational(total_staked, total_stakable);
let falloff = Perquintill::from_percent(5);
let adjustment = compute_inflation(stake, ideal_stake, falloff);
let staking_inflation =
min_annual_inflation.saturating_add(delta_annual_inflation * adjustment);

let max_payout = period_fraction * max_annual_inflation * total_stakable;
let staking_payout = (period_fraction * staking_inflation) * total_stakable;
let rest = max_payout.saturating_sub(staking_payout);

let other_issuance = total_stakable.saturating_sub(total_staked);
if total_staked > other_issuance {
let _cap_rest =
Perquintill::from_rational(other_issuance, total_staked) * staking_payout;
// We don't do anything with this, but if we wanted to, we could introduce a cap on the
// treasury amount with: `rest = rest.min(cap_rest);`
}
(staking_payout, rest)
}

#[test]
fn test_fees_and_tip_split() {
new_test_ext().execute_with(|| {
Expand Down Expand Up @@ -425,13 +487,99 @@ mod tests {

#[test]
fn era_payout_should_give_sensible_results() {
assert_eq!(
era_payout(75, 100, Perquintill::from_percent(10), Perquintill::one(), 0,),
(10, 0)
let payout =
deprecated_era_payout(75, 100, Perquintill::from_percent(10), Perquintill::one(), 0);
assert_eq!(payout, (10, 0));

let payout =
deprecated_era_payout(80, 100, Perquintill::from_percent(10), Perquintill::one(), 0);
assert_eq!(payout, (6, 4));
}

#[test]
fn relay_era_payout_should_give_sensible_results() {
let params = EraPayoutParams {
total_staked: 75,
total_stakable: 100,
ideal_stake: Perquintill::from_percent(75),
max_annual_inflation: Perquintill::from_percent(10),
min_annual_inflation: Perquintill::from_rational(25u64, 1000u64),
falloff: Perquintill::from_percent(5),
period_fraction: Perquintill::one(),
legacy_auction_proportion: None,
};
assert_eq!(relay_era_payout(params), (10, 0));

let params = EraPayoutParams {
total_staked: 80,
total_stakable: 100,
ideal_stake: Perquintill::from_percent(75),
max_annual_inflation: Perquintill::from_percent(10),
min_annual_inflation: Perquintill::from_rational(25u64, 1000u64),
falloff: Perquintill::from_percent(5),
period_fraction: Perquintill::one(),
legacy_auction_proportion: None,
};
assert_eq!(relay_era_payout(params), (6, 4));
}

#[test]
fn relay_era_payout_should_give_same_results_as_era_payout() {
let total_staked = 1_000_000;
let total_stakable = 2_000_000;
let max_annual_inflation = Perquintill::from_percent(10);
let period_fraction = Perquintill::from_percent(25);
let auctioned_slots = 30;

let params = EraPayoutParams {
total_staked,
total_stakable,
ideal_stake: Perquintill::from_percent(75),
max_annual_inflation,
min_annual_inflation: Perquintill::from_rational(25u64, 1000u64),
falloff: Perquintill::from_percent(5),
period_fraction,
legacy_auction_proportion: Some(Perquintill::from_rational(
auctioned_slots.min(60),
200u64,
)),
};

let payout = deprecated_era_payout(
total_staked,
total_stakable,
max_annual_inflation,
period_fraction,
auctioned_slots,
);
assert_eq!(
era_payout(80, 100, Perquintill::from_percent(10), Perquintill::one(), 0,),
(6, 4)
assert_eq!(relay_era_payout(params), payout);

let total_staked = 1_900_000;
let total_stakable = 2_000_000;
let auctioned_slots = 60;

let params = EraPayoutParams {
total_staked,
total_stakable,
ideal_stake: Perquintill::from_percent(75),
max_annual_inflation,
min_annual_inflation: Perquintill::from_rational(25u64, 1000u64),
falloff: Perquintill::from_percent(5),
period_fraction,
legacy_auction_proportion: Some(Perquintill::from_rational(
auctioned_slots.min(60),
200u64,
)),
};

let payout = deprecated_era_payout(
total_staked,
total_stakable,
max_annual_inflation,
period_fraction,
auctioned_slots,
);

assert_eq!(relay_era_payout(params), payout);
}
}
5 changes: 4 additions & 1 deletion polkadot/runtime/westend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pallet-multisig = { workspace = true }
pallet-nomination-pools = { workspace = true }
pallet-conviction-voting = { workspace = true }
pallet-offences = { workspace = true }
pallet-parameters = { workspace = true }
pallet-preimage = { workspace = true }
pallet-proxy = { workspace = true }
pallet-recovery = { workspace = true }
Expand All @@ -79,7 +80,6 @@ pallet-scheduler = { workspace = true }
pallet-session = { workspace = true }
pallet-society = { workspace = true }
pallet-staking = { workspace = true }
pallet-staking-reward-curve = { workspace = true, default-features = true }
pallet-staking-runtime-api = { workspace = true }
pallet-delegated-staking = { workspace = true }
pallet-state-trie-migration = { workspace = true }
Expand Down Expand Up @@ -173,6 +173,7 @@ std = [
"pallet-nomination-pools/std",
"pallet-offences-benchmarking?/std",
"pallet-offences/std",
"pallet-parameters/std",
"pallet-preimage/std",
"pallet-proxy/std",
"pallet-recovery/std",
Expand Down Expand Up @@ -260,6 +261,7 @@ runtime-benchmarks = [
"pallet-nomination-pools/runtime-benchmarks",
"pallet-offences-benchmarking/runtime-benchmarks",
"pallet-offences/runtime-benchmarks",
"pallet-parameters/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks",
"pallet-recovery/runtime-benchmarks",
Expand Down Expand Up @@ -318,6 +320,7 @@ try-runtime = [
"pallet-multisig/try-runtime",
"pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime",
"pallet-parameters/try-runtime",
"pallet-preimage/try-runtime",
"pallet-proxy/try-runtime",
"pallet-recovery/try-runtime",
Expand Down
Loading

0 comments on commit 6e520eb

Please sign in to comment.