Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Update polkadot inflation to take into account auctions #5872

Merged
merged 12 commits into from
Nov 8, 2022
Merged
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.

2 changes: 2 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking-reward-fn = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-vesting = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
Expand Down Expand Up @@ -84,6 +85,7 @@ std = [
"pallet-beefy-mmr/std",
"pallet-session/std",
"pallet-staking/std",
"pallet-staking-reward-fn/std",
"pallet-timestamp/std",
"pallet-vesting/std",
"pallet-transaction-payment/std",
Expand Down
13 changes: 12 additions & 1 deletion runtime/common/src/auctions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ pub mod pallet {
#[pallet::getter(fn auction_counter)]
pub type AuctionCounter<T> = StorageValue<_, AuctionIndex, ValueQuery>;

// TODO: Migration:
// We need to go over https://kusama.subscan.io/event?module=auctions&event=auctionclosed&page=1&address=&startDate=&endDate=&startBlock=&endBlock=&timeType=date&version=9291, and grab the paraId of the `slots::Leased` events emitted in the same block, if any.
// TODO: will this work with how para-ids are swapped/extended? Yes afaik. We should not care how stuff is swapped/extended. We only want to track: how many parachains got auctions, that are currently active.
#[pallet::storage]
#[pallet::getter(fn auctioned_winner_para_ids)]
#[pallet::unbounded]
pub type AuctionedWinnerParaIds<T> = StorageValue<_, Vec<ParaId>, ValueQuery>;

/// Information relating to the current auction, if there is one.
///
/// The first item in the tuple is the lease period index that the first of the four
Expand Down Expand Up @@ -609,7 +617,10 @@ impl<T: Config> Pallet<T> {
});
}
},
Ok(()) => {}, // Nothing to report.
Ok(()) => {
// record the winner para-ids.
AuctionedWinnerParaIds::<T>::mutate(|a| a.push(para));
},
}
}

Expand Down
41 changes: 41 additions & 0 deletions runtime/common/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

use crate::NegativeImbalance;
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
use primitives::v2::Balance;
use sp_runtime::Perquintill;

/// Logic for the author to get a portion of fees.
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
Expand Down Expand Up @@ -57,6 +59,45 @@ where
}
}

pub fn era_payout(
total_staked: Balance,
non_gilt_issuance: 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);
Comment on lines +75 to +76
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this hardcoded amount problematic?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - it just sets an effective upper limit to how much of the inflation can be accounted for by the slot auctions.


// 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, non_gilt_issuance);
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 * non_gilt_issuance;
let staking_payout = (period_fraction * staking_inflation) * non_gilt_issuance;
let rest = max_payout.saturating_sub(staking_payout);

let other_issuance = non_gilt_issuance.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)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 0 additions & 2 deletions runtime/kusama/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ pallet-session = { git = "https://github.com/paritytech/substrate", branch = "ma
pallet-society = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking-reward-fn = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = {git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
Expand Down Expand Up @@ -170,7 +169,6 @@ std = [
"pallet-session/std",
"pallet-society/std",
"pallet-staking/std",
"pallet-staking-reward-fn/std",
"pallet-timestamp/std",
"pallet-tips/std",
"pallet-treasury/std",
Expand Down
59 changes: 16 additions & 43 deletions runtime/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,59 +504,32 @@ impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
type Score = sp_npos_elections::VoteWeight;
}

fn era_payout(
total_staked: Balance,
non_gilt_issuance: Balance,
max_annual_inflation: Perquintill,
period_fraction: Perquintill,
auctioned_slots: u64,
) -> (Balance, Balance) {
use pallet_staking_reward_fn::compute_inflation;
use sp_arithmetic::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, non_gilt_issuance);
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 * non_gilt_issuance;
let staking_payout = (period_fraction * staking_inflation) * non_gilt_issuance;
let rest = max_payout.saturating_sub(staking_payout);

let other_issuance = non_gilt_issuance.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)
}

pub struct EraPayout;
impl pallet_staking::EraPayout<Balance> for EraPayout {
fn era_payout(
total_staked: Balance,
_total_issuance: Balance,
era_duration_millis: u64,
) -> (Balance, Balance) {
// TODO: #3011 Update with proper auctioned slots tracking.
// This should be fine for the first year of parachains.
let auctioned_slots: u64 = auctions::Pallet::<Runtime>::auction_counter().into();
let auctioned_slots = {
// all para-ids that have been leased out.
let auctioned_winner_para_ids = Auctions::auctioned_winner_para_ids();
// and all para-ids that are not active.
KiChjang marked this conversation as resolved.
Show resolved Hide resolved
let active_para_ids = Paras::parachains();
// the intersection of which is the number of parachain's which we should take into
// account for inflation.
auctioned_winner_para_ids
.into_iter()
.filter(|i| active_para_ids.contains(i))
.count() as u64
// note: we could speed up this block a bit with sorting and binary searching, but it
// does not seem worthwhile for a few hundred parachains at most.
};

const MAX_ANNUAL_INFLATION: Perquintill = Perquintill::from_percent(10);
const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100;

era_payout(
runtime_common::impls::era_payout(
total_staked,
Gilt::issuance().non_gilt,
MAX_ANNUAL_INFLATION,
Expand Down
38 changes: 37 additions & 1 deletion runtime/polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,42 @@ type SlashCancelOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 4>,
>;

pub struct EraPayout;
impl pallet_staking::EraPayout<Balance> for EraPayout {
fn era_payout(
total_staked: Balance,
_total_issuance: Balance,
era_duration_millis: u64,
) -> (Balance, Balance) {
let auctioned_slots = {
// all para-ids that have been leased out.
let auctioned_winner_para_ids = Auctions::auctioned_winner_para_ids();
// and all para-ids that are not active.
KiChjang marked this conversation as resolved.
Show resolved Hide resolved
let active_para_ids = Paras::parachains();
// the intersection of which is the number of parachain's which we should take into
// account for inflation.
auctioned_winner_para_ids
.into_iter()
.filter(|i| active_para_ids.contains(i))
.count() as u64
// note: we could speed up this block a bit with sorting and binary searching, but it
// does not seem worthwhile for a few hundred parachains at most.
};

const MAX_ANNUAL_INFLATION: Perquintill = Perquintill::from_percent(10);
const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100;

runtime_common::impls::era_payout(
total_staked,
// Polkadot has no notion of gilts, the entire issuance is non-guilt.
Balances::total_issuance(),
kianenigma marked this conversation as resolved.
Show resolved Hide resolved
MAX_ANNUAL_INFLATION,
Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR),
auctioned_slots,
)
}
}

impl pallet_staking::Config for Runtime {
type MaxNominations = MaxNominations;
type Currency = Balances;
Expand All @@ -552,7 +588,7 @@ impl pallet_staking::Config for Runtime {
// A super-majority of the council can cancel the slash.
type SlashCancelOrigin = SlashCancelOrigin;
type SessionInterface = Self;
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type EraPayout = EraPayout;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type NextNewSession = Session;
Expand Down