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

Staking Reward Rate Runtime API #13416

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
710bab9
Adds StakingAPI_nominations_quota and NominationPoolsApi_balanceToPoi…
gpestana Jan 10, 2023
11c4f61
Adds balance param to api_nominations_quota
gpestana Jan 11, 2023
3268088
Update frame/nomination-pools/src/lib.rs
gpestana Jan 13, 2023
ca2ed2f
Update frame/nomination-pools/src/lib.rs
gpestana Jan 13, 2023
a31efce
Addresses comments - returns zero instead of error in runtime api
gpestana Jan 13, 2023
9a1175f
api_inflation_rate runtime api
Feb 19, 2023
6ca5f9a
+ comments
Feb 21, 2023
fedd974
Merge branch 'master' into rb-inflation-runtime-api
Feb 21, 2023
ce15e86
remove api version
Feb 21, 2023
174fc7b
increment api version
Feb 22, 2023
2b14048
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
Feb 22, 2023
2e1524d
polish
Feb 22, 2023
3250e02
".git/.scripts/commands/fmt/fmt.sh"
Feb 22, 2023
11209f2
mv function
Feb 22, 2023
5be4a45
fix types
Feb 23, 2023
85795cf
use inflation constants
Feb 23, 2023
24ee1db
+ note
Feb 23, 2023
4cc19cc
formatting
Feb 23, 2023
560f144
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
Feb 23, 2023
9699959
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
Feb 24, 2023
a665ec0
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
Feb 26, 2023
b35c166
add TODO
Feb 27, 2023
8dd63af
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
May 14, 2023
a5cc54d
rename to reward_rate
May 14, 2023
e08a2fd
use reward_rate
May 14, 2023
37b0fbf
add min & max inflation constants
May 14, 2023
7763889
add calculations & test boilerplate
May 14, 2023
705f381
amend max inflation
May 14, 2023
b990b97
curve before ideal_stake working
May 14, 2023
8bed2de
calcs
May 14, 2023
d5924c7
remove floats & fix test
May 14, 2023
33db2ea
tidy up
May 14, 2023
9495f16
fmt
May 14, 2023
f51f33c
amend comment
May 14, 2023
8de9751
calc fixes
May 14, 2023
75f70bc
fmt
May 14, 2023
a5a70b1
use saturating
May 14, 2023
28bf6c6
remove println
May 14, 2023
42d5b8a
Merge remote-tracking branch 'origin/master' into rb-inflation-runtim…
May 14, 2023
a86ebcd
tidy up
May 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions bin/node/runtime/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ pub mod currency {
}
}

/// Inflation parameters.
pub mod inflation {
use sp_runtime::Perquintill;
// NOTE: Changes to these parameters must also be applied in
// `pallet_staking_reward_curve::build!`.
pub const IDEAL_STAKE_BASE: Perquintill = Perquintill::from_percent(75);
pub const FALLOFF: Perquintill = Perquintill::from_percent(5);
pub const MIN_INFLATION: Perquintill = Perquintill::from_perthousand(25);
pub const MAX_INFLATION: Perquintill = Perquintill::from_percent(10);
}

/// Time.
pub mod time {
use node_primitives::{BlockNumber, Moment};
Expand Down
7 changes: 6 additions & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ use impls::{AllianceProposalProvider, Author, CreditToBlockAuthor};

/// Constant values used within the runtime.
pub mod constants;
use constants::{currency::*, time::*};
use constants::{currency::*, inflation::*, time::*};
use sp_runtime::generic::Era;

/// Generated voter bag information.
Expand Down Expand Up @@ -538,6 +538,8 @@ impl pallet_session::historical::Config for Runtime {
type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
}

// NOTE: Changes to `min_inflation, `max_inflation`, `ideal_stake` and `falloff` must also be
// applied in constants::inflation.
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_025_000,
Expand Down Expand Up @@ -2101,6 +2103,9 @@ impl_runtime_apis! {
}

impl pallet_staking_runtime_api::StakingApi<Block, Balance> for Runtime {
fn reward_rate() -> Perquintill {
Staking::api_reward_rate(MIN_INFLATION, MAX_INFLATION, IDEAL_STAKE_BASE, FALLOFF)
}
fn nominations_quota(balance: Balance) -> u32 {
Staking::api_nominations_quota(balance)
}
Expand Down
2 changes: 2 additions & 0 deletions frame/staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, features = [
"historical",
], path = "../session" }
pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" }
pallet-staking-reward-fn = { version = "4.0.0-dev", default-features = false, path = "./reward-fn" }
sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" }
frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" }
log = { version = "0.4.17", default-features = false }
Expand Down Expand Up @@ -62,6 +63,7 @@ std = [
"sp-runtime/std",
"sp-staking/std",
"pallet-session/std",
"pallet-staking-reward-fn/std",
rossbulat marked this conversation as resolved.
Show resolved Hide resolved
"frame-system/std",
"pallet-authorship/std",
"sp-application-crypto/std",
Expand Down
2 changes: 2 additions & 0 deletions frame/staking/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" }

[features]
default = ["std"]
std = [
"codec/std",
"sp-api/std",
"sp-runtime/std"
]
5 changes: 5 additions & 0 deletions frame/staking/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
#![cfg_attr(not(feature = "std"), no_std)]

use codec::Codec;
use sp_runtime::Perquintill;

sp_api::decl_runtime_apis! {
#[api_version(2)]
pub trait StakingApi<Balance>
where
Balance: Codec,
{
/// Returns the current staking reward rate.
fn reward_rate() -> Perquintill;

/// Returns the nominations quota for a nominator with a given balance.
fn nominations_quota(balance: Balance) -> u32;
}
Expand Down
42 changes: 41 additions & 1 deletion frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
use pallet_session::historical;
use sp_runtime::{
traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero},
Perbill,
Perbill, Perquintill,
};
use sp_staking::{
offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
Expand Down Expand Up @@ -974,6 +974,46 @@ impl<T: Config> Pallet<T> {
}

impl<T: Config> Pallet<T> {
/// Returns the current staking reward rate.
pub fn api_reward_rate(
Copy link
Contributor

@gui1117 gui1117 Jun 9, 2023

Choose a reason for hiding this comment

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

Staking is currently unaware of the reward rate, this implementation makes assumption on the implementation of Config trait.

The payout is abstracted through associated type Config::EraPayout which bounds the trait EraPayout
Either some assumption should be enforced on the implementation of EraPayout on the rate can be retrieved by calling the payout for an era of one year payout(current_total_staked, current_total_issuance, one_year).
This doesn't look so good, but could be fine.

Better would be to:

  • either add a method to EraPayout trait to be able to retrieve the reward rate
  • or expose the rate from the node.

Copy link
Author

Choose a reason for hiding this comment

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

Indeed. The calculations currently in place were based on an outdated calculation of PJS. We can simply refer to era payout to determine the inflation on a per-era basis.

min_inflation: Perquintill,
max_inflation: Perquintill,
ideal_stake: Perquintill,
falloff: Perquintill,
) -> Perquintill {
match ActiveEra::<T>::get() {
Some(active_era) => {
let staked = ErasTotalStake::<T>::get(active_era.index);
let total_issuance = T::Currency::total_issuance();
let staked_percent = Perquintill::from_rational(staked, total_issuance);

// NOTE: The JavaScript implemenation considers 2 parameters, `auctionMax` and
// `auctionAdjust` in the following calculation:
//
// Math.min(auctionMax, numAuctions.toNumber()) * auctionAdjust;
//
// `auctionMax` is always 0 on PJS Apps and Staking Dashboard. This calculation is
// therefore being ignored here for now.
let ideal_interest = max_inflation / ideal_stake;
let curve = if staked_percent <= ideal_stake {
(ideal_interest.saturating_sub(min_inflation / ideal_stake))
.saturating_mul(staked_percent)
} else {
let curve_base =
ideal_interest.saturating_mul(ideal_stake).saturating_sub(min_inflation);
let curve_power = (staked_percent - ideal_stake).int_div(falloff);
let curve_multiplier = Perquintill::from_percent(1) /
Perquintill::from_percent(2u64.pow(curve_power as u32));
curve_base.saturating_mul(curve_multiplier)
};

let reward_rate = min_inflation + curve;
reward_rate
},
None => Perquintill::zero(),
}
}

/// Returns the current nominations quota for nominators.
///
/// Used by the runtime API.
Expand Down
15 changes: 15 additions & 0 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,21 @@ fn rewards_should_work() {
});
}

#[test]
fn api_reward_rate_works() {
ExtBuilder::default().build_and_execute(|| {
assert_eq!(
Pallet::<Test>::api_reward_rate(
Perquintill::from_perthousand(25),
Perquintill::from_percent(10),
Perquintill::from_percent(75),
Perquintill::from_percent(5)
),
Perquintill::from_float(0.0250000249999995)
);
})
}

#[test]
fn staking_should_work() {
ExtBuilder::default().nominate(false).build_and_execute(|| {
Expand Down