Skip to content

Commit

Permalink
Westend: Constant yearly emission (#5999)
Browse files Browse the repository at this point in the history
Testing the approach of this before it goes live on Polkadot
polkadot-fellows/runtimes#471

---------

Signed-off-by: Oliver Tale-Yazdi <[email protected]>
Co-authored-by: Dónal Murray <[email protected]>
  • Loading branch information
ggwpez and seadanda authored Oct 14, 2024
1 parent d7f01a1 commit aca11dc
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ alloy-primitives = { version = "0.4.2", default-features = false }
alloy-sol-types = { version = "0.4.2", default-features = false }
always-assert = { version = "0.1" }
anyhow = { version = "1.0.81", default-features = false }
approx = { version = "0.5.1" }
aquamarine = { version = "0.5.0" }
arbitrary = { version = "1.3.2" }
ark-bls12-377 = { version = "0.4.0", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions polkadot/runtime/westend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ xcm-builder = { workspace = true }
xcm-runtime-apis = { workspace = true }

[dev-dependencies]
approx = { workspace = true }
tiny-keccak = { features = ["keccak"], workspace = true }
sp-keyring = { workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
Expand Down
47 changes: 20 additions & 27 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ use polkadot_runtime_common::{
elections::OnChainAccuracy,
identity_migrator, impl_runtime_weights,
impls::{
relay_era_payout, ContainsParts, EraPayoutParams, LocatableAssetConverter, ToAuthor,
VersionedLocatableAsset, VersionedLocationConverter,
ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset,
VersionedLocationConverter,
},
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
traits::OnSwap,
Expand Down Expand Up @@ -681,33 +681,26 @@ impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
pub struct EraPayout;
impl pallet_staking::EraPayout<Balance> for EraPayout {
fn era_payout(
total_staked: Balance,
total_issuance: Balance,
_total_staked: Balance,
_total_issuance: Balance,
era_duration_millis: u64,
) -> (Balance, Balance) {
const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100;

let params = EraPayoutParams {
total_staked,
total_stakable: total_issuance,
ideal_stake: dynamic_params::inflation::IdealStake::get(),
max_annual_inflation: dynamic_params::inflation::MaxInflation::get(),
min_annual_inflation: dynamic_params::inflation::MinInflation::get(),
falloff: dynamic_params::inflation::Falloff::get(),
period_fraction: Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR),
legacy_auction_proportion: if dynamic_params::inflation::UseAuctionSlots::get() {
let auctioned_slots = parachains_paras::Parachains::<Runtime>::get()
.into_iter()
// all active para-ids that do not belong to a system chain is the number of
// parachains that we should take into account for inflation.
.filter(|i| *i >= 2000.into())
.count() as u64;
Some(Perquintill::from_rational(auctioned_slots.min(60), 200u64))
} else {
None
},
};
relay_era_payout(params)
const MILLISECONDS_PER_YEAR: u64 = (1000 * 3600 * 24 * 36525) / 100;
// A normal-sized era will have 1 / 365.25 here:
let relative_era_len =
FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into());

// Fixed total TI that we use as baseline for the issuance.
let fixed_total_issuance: i128 = 5_216_342_402_773_185_773;
let fixed_inflation_rate = FixedU128::from_rational(8, 100);
let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance);

let era_emission = relative_era_len.saturating_mul_int(yearly_emission);
// 15% to treasury, as per Polkadot ref 1139.
let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission);
let to_stakers = era_emission.saturating_sub(to_treasury);

(to_stakers.saturated_into(), to_treasury.saturated_into())
}
}

Expand Down
95 changes: 95 additions & 0 deletions polkadot/runtime/westend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@
use std::collections::HashSet;

use crate::{xcm_config::LocationConverter, *};
use approx::assert_relative_eq;
use frame_support::traits::WhitelistedStorageKeys;
use pallet_staking::EraPayout;
use sp_core::{crypto::Ss58Codec, hexdisplay::HexDisplay};
use sp_keyring::AccountKeyring::Alice;
use xcm_runtime_apis::conversions::LocationToAccountHelper;

const MILLISECONDS_PER_HOUR: u64 = 60 * 60 * 1000;

#[test]
fn remove_keys_weight_is_sensible() {
use polkadot_runtime_common::crowdloan::WeightInfo;
Expand Down Expand Up @@ -311,3 +315,94 @@ fn location_conversion_works() {
assert_eq!(got, expected, "{}", tc.description);
}
}

#[test]
fn staking_inflation_correct_single_era() {
let (to_stakers, to_treasury) = super::EraPayout::era_payout(
123, // ignored
456, // ignored
MILLISECONDS_PER_HOUR,
);

assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64, max_relative = 0.01);
assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64, max_relative = 0.01);
// Total per hour is ~47.6 WND
assert_relative_eq!(
(to_stakers as f64 + to_treasury as f64),
(4_760 * CENTS) as f64,
max_relative = 0.001
);
}

#[test]
fn staking_inflation_correct_longer_era() {
// Twice the era duration means twice the emission:
let (to_stakers, to_treasury) = super::EraPayout::era_payout(
123, // ignored
456, // ignored
2 * MILLISECONDS_PER_HOUR,
);

assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64 * 2.0, max_relative = 0.001);
assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64 * 2.0, max_relative = 0.001);
}

#[test]
fn staking_inflation_correct_whole_year() {
let (to_stakers, to_treasury) = super::EraPayout::era_payout(
123, // ignored
456, // ignored
(36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year
);

// Our yearly emissions is about 417k WND:
let yearly_emission = 417_307 * UNITS;
assert_relative_eq!(
to_stakers as f64 + to_treasury as f64,
yearly_emission as f64,
max_relative = 0.001
);

assert_relative_eq!(to_stakers as f64, yearly_emission as f64 * 0.85, max_relative = 0.001);
assert_relative_eq!(to_treasury as f64, yearly_emission as f64 * 0.15, max_relative = 0.001);
}

// 10 years into the future, our values do not overflow.
#[test]
fn staking_inflation_correct_not_overflow() {
let (to_stakers, to_treasury) = super::EraPayout::era_payout(
123, // ignored
456, // ignored
(36525 * 24 * MILLISECONDS_PER_HOUR) / 10, // 10 years
);
let initial_ti: i128 = 5_216_342_402_773_185_773;
let projected_total_issuance = (to_stakers as i128 + to_treasury as i128) + initial_ti;

// In 2034, there will be about 9.39 million WND in existence.
assert_relative_eq!(
projected_total_issuance as f64,
(9_390_000 * UNITS) as f64,
max_relative = 0.001
);
}

// Print percent per year, just as convenience.
#[test]
fn staking_inflation_correct_print_percent() {
let (to_stakers, to_treasury) = super::EraPayout::era_payout(
123, // ignored
456, // ignored
(36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year
);
let yearly_emission = to_stakers + to_treasury;
let mut ti: i128 = 5_216_342_402_773_185_773;

for y in 0..10 {
let new_ti = ti + yearly_emission as i128;
let inflation = 100.0 * (new_ti - ti) as f64 / ti as f64;
println!("Year {y} inflation: {inflation}%");
ti = new_ti;

assert!(inflation <= 8.0 && inflation > 2.0, "sanity check");
}
}
15 changes: 15 additions & 0 deletions prdoc/pr_5999.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: "Westend: Constant yearly emission"

doc:
- audience: Runtime User
description: |
Integrating the new inflation approach from https://github.com/polkadot-fellows/runtimes/pull/471
into Westend first to check that it is working.


crates:
- name: westend-runtime
bump: patch

0 comments on commit aca11dc

Please sign in to comment.