Skip to content

Commit

Permalink
Staking and nomination pools runtime API improvements (paritytech#13119)
Browse files Browse the repository at this point in the history
* Adds StakingAPI_nominations_quota and NominationPoolsApi_balanceToPoint and NominationPoolsApi_pointsToBalance runtime APIs

* Adds balance param to api_nominations_quota

* Update frame/nomination-pools/src/lib.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Update frame/nomination-pools/src/lib.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Addresses comments - returns zero instead of error in runtime api

* Update frame/staking/runtime-api/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/staking/runtime-api/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Addresses PR comments

* Update frame/nomination-pools/runtime-api/Cargo.toml

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Fixes points_to_balance logic; adds tests

* test comment fix

* Update frame/nomination-pools/runtime-api/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/nomination-pools/runtime-api/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Fix block pruning (paritytech#13323)

* Referendum proposal's metadata (paritytech#12568)

* referenda metadata

* todo comment

* remove TODO, update rustdocs

* referenda clear_metadata origin signed or root

* referenda metadata unit tests

* drop schema type for referenda metadata

* remove metadata type

* referenda metadata benches

* note different preimages

* metadata for democracy pallet

* metadata democracy pallet tests and benches

* fix cargo clippy

* update docs

* ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy

* ".git/.scripts/bench-bot.sh" pallet dev pallet_referenda

* Update the doc frame/democracy/src/lib.rs

Co-authored-by: Roman Useinov <roman.useinov@gmail.com>

* Update the doc frame/democracy/src/lib.rs

Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com>

* reference instead clone for take

Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com>

* error rename BadMetadata to PreimageNotExist

* clear metadata within internal_cancel_referendum fn

* remove redundant clone

* collapse metadata api into one set_metadata method

* fmt

* review fixes

* not request preimage on set_metadata

* rename events and update docs

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_democracy

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_referenda

* rename reset_metadata to transfer_metadata

---------

Co-authored-by: command-bot <>
Co-authored-by: Roman Useinov <roman.useinov@gmail.com>
Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com>

* Improve test coverage of the `Notifications` protocol (paritytech#13033)

* Add handler and upgrade tests

* Add tests for `behaviour.rs`

* Apply review comments

* Update dependencies

* Apply suggestions from code review

Co-authored-by: Dmitry Markin <dmitry@markin.tech>

* Apply review comments

* Fix clippy

* Update mockall

* Apply review comment

---------

Co-authored-by: Dmitry Markin <dmitry@markin.tech>

* refactors runtime API logic to own pallet impl block

* removes unrelated changes

* Fixes cargo doc comments lint

* fixes node cargo

* fixes comment

* restart ci

* restart ci

* restart ci

---------

Co-authored-by: Anton <anton.kalyaev@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: parity-processbot <>
Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com>
Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com>
Co-authored-by: Roman Useinov <roman.useinov@gmail.com>
Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com>
Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com>
Co-authored-by: Dmitry Markin <dmitry@markin.tech>
  • Loading branch information
9 people authored and ukint-vs committed Apr 10, 2023
1 parent 0e3de50 commit cb5cbed
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 45 deletions.
10 changes: 10 additions & 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 @@ -141,6 +141,7 @@ members = [
"frame/staking",
"frame/staking/reward-curve",
"frame/staking/reward-fn",
"frame/staking/runtime-api",
"frame/state-trie-migration",
"frame/sudo",
"frame/root-offences",
Expand Down
2 changes: 2 additions & 0 deletions bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = ".
pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true }
pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" }
pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/reward-curve" }
pallet-staking-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/runtime-api" }
pallet-state-trie-migration = { version = "4.0.0-dev", default-features = false, path = "../../../frame/state-trie-migration" }
pallet-scheduler = { version = "4.0.0-dev", default-features = false, path = "../../../frame/scheduler" }
pallet-society = { version = "4.0.0-dev", default-features = false, path = "../../../frame/society" }
Expand Down Expand Up @@ -177,6 +178,7 @@ std = [
"sp-runtime/std",
"sp-staking/std",
"pallet-staking/std",
"pallet-staking-runtime-api/std",
"pallet-state-trie-migration/std",
"sp-session/std",
"pallet-sudo/std",
Expand Down
18 changes: 16 additions & 2 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,8 +1986,22 @@ impl_runtime_apis! {
}

impl pallet_nomination_pools_runtime_api::NominationPoolsApi<Block, AccountId, Balance> for Runtime {
fn pending_rewards(member_account: AccountId) -> Balance {
NominationPools::pending_rewards(member_account).unwrap_or_default()
fn pending_rewards(who: AccountId) -> Balance {
NominationPools::api_pending_rewards(who).unwrap_or_default()
}

fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance {
NominationPools::api_points_to_balance(pool_id, points)
}

fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance {
NominationPools::api_balance_to_points(pool_id, new_funds)
}
}

impl pallet_staking_runtime_api::StakingApi<Block, Balance> for Runtime {
fn nominations_quota(balance: Balance) -> u32 {
Staking::api_nominations_quota(balance)
}
}

Expand Down
2 changes: 2 additions & 0 deletions frame/nomination-pools/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" }
pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" }

[features]
default = ["std"]
std = [
"codec/std",
"sp-api/std",
"sp-std/std",
"pallet-nomination-pools/std",
]
13 changes: 11 additions & 2 deletions frame/nomination-pools/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@
#![cfg_attr(not(feature = "std"), no_std)]

use codec::Codec;
use pallet_nomination_pools::PoolId;

sp_api::decl_runtime_apis! {
/// Runtime api for accessing information about nomination pools.
pub trait NominationPoolsApi<AccountId, Balance>
where AccountId: Codec, Balance: Codec
where
AccountId: Codec,
Balance: Codec,
{
/// Returns the pending rewards for the member that the AccountId was given for.
fn pending_rewards(member: AccountId) -> Balance;
fn pending_rewards(who: AccountId) -> Balance;

/// Returns the equivalent balance of `points` for a given pool.
fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance;

/// Returns the equivalent points of `new_funds` for a given pool.
fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance;
}
}
62 changes: 44 additions & 18 deletions frame/nomination-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2142,24 +2142,6 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
/// Returns the pending rewards for the specified `member_account`.
///
/// In the case of error, `None` is returned.
pub fn pending_rewards(member_account: T::AccountId) -> Option<BalanceOf<T>> {
if let Some(pool_member) = PoolMembers::<T>::get(member_account) {
if let Some((reward_pool, bonded_pool)) = RewardPools::<T>::get(pool_member.pool_id)
.zip(BondedPools::<T>::get(pool_member.pool_id))
{
let current_reward_counter = reward_pool
.current_reward_counter(pool_member.pool_id, bonded_pool.points)
.ok()?;
return pool_member.pending_rewards(current_reward_counter).ok()
}
}

None
}

/// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS.
///
/// It is the responsibility of the depositor to put these funds into the pool initially. Upon
Expand Down Expand Up @@ -2579,6 +2561,50 @@ impl<T: Config> Pallet<T> {
}
}

impl<T: Config> Pallet<T> {
/// Returns the pending rewards for the specified `who` account.
///
/// In the case of error, `None` is returned. Used by runtime API.
pub fn api_pending_rewards(who: T::AccountId) -> Option<BalanceOf<T>> {
if let Some(pool_member) = PoolMembers::<T>::get(who) {
if let Some((reward_pool, bonded_pool)) = RewardPools::<T>::get(pool_member.pool_id)
.zip(BondedPools::<T>::get(pool_member.pool_id))
{
let current_reward_counter = reward_pool
.current_reward_counter(pool_member.pool_id, bonded_pool.points)
.ok()?;
return pool_member.pending_rewards(current_reward_counter).ok()
}
}

None
}

/// Returns the points to balance conversion for a specified pool.
///
/// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API.
pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf<T>) -> BalanceOf<T> {
if let Some(pool) = BondedPool::<T>::get(pool_id) {
pool.points_to_balance(points)
} else {
Zero::zero()
}
}

/// Returns the equivalent `new_funds` balance to point conversion for a specified pool.
///
/// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API.
pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf<T>) -> BalanceOf<T> {
if let Some(pool) = BondedPool::<T>::get(pool_id) {
let bonded_balance =
T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero());
Pallet::<T>::balance_to_point(bonded_balance, pool.points, new_funds)
} else {
Zero::zero()
}
}
}

impl<T: Config> OnStakerSlash<T::AccountId, BalanceOf<T>> for Pallet<T> {
fn on_slash(
pool_account: &T::AccountId,
Expand Down
86 changes: 63 additions & 23 deletions frame/nomination-pools/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,46 @@ mod bonded_pool {
})
}

#[test]
fn api_points_to_balance_works() {
ExtBuilder::default().build_and_execute(|| {
assert!(BondedPool::<Runtime>::get(1).is_some());
assert_eq!(Pallet::<Runtime>::api_points_to_balance(1, 10), 10);

// slash half of the pool's balance. expected result of `fn api_points_to_balance`
// to be 1/2 of the pool's balance.
StakingMock::set_bonded_balance(
default_bonded_account(),
Pools::depositor_min_bond() / 2,
);
assert_eq!(Pallet::<Runtime>::api_points_to_balance(1, 10), 5);

// if pool does not exist, points to balance ratio is 0.
assert_eq!(BondedPool::<Runtime>::get(2), None);
assert_eq!(Pallet::<Runtime>::api_points_to_balance(2, 10), 0);
})
}

#[test]
fn api_balance_to_points_works() {
ExtBuilder::default().build_and_execute(|| {
assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 0), 0);
assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 10), 10);

// slash half of the pool's balance. expect result of `fn api_balance_to_points`
// to be 2 * of the balance to add to the pool.
StakingMock::set_bonded_balance(
default_bonded_account(),
Pools::depositor_min_bond() / 2,
);
assert_eq!(Pallet::<Runtime>::api_balance_to_points(1, 10), 20);

// if pool does not exist, balance to points ratio is 0.
assert_eq!(BondedPool::<Runtime>::get(2), None);
assert_eq!(Pallet::<Runtime>::api_points_to_balance(2, 10), 0);
})
}

#[test]
fn ok_to_join_with_works() {
ExtBuilder::default().build_and_execute(|| {
Expand Down Expand Up @@ -1305,51 +1345,51 @@ mod claim_payout {
ExtBuilder::default().build_and_execute(|| {
let ed = Balances::minimum_balance();

assert_eq!(Pools::pending_rewards(10), Some(0));
assert_eq!(Pools::api_pending_rewards(10), Some(0));
Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap();
assert_eq!(Pools::pending_rewards(10), Some(30));
assert_eq!(Pools::pending_rewards(20), None);
assert_eq!(Pools::api_pending_rewards(10), Some(30));
assert_eq!(Pools::api_pending_rewards(20), None);

Balances::make_free_balance_be(&20, ed + 10);
assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));

assert_eq!(Pools::pending_rewards(10), Some(30));
assert_eq!(Pools::pending_rewards(20), Some(0));
assert_eq!(Pools::api_pending_rewards(10), Some(30));
assert_eq!(Pools::api_pending_rewards(20), Some(0));

Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap();

assert_eq!(Pools::pending_rewards(10), Some(30 + 50));
assert_eq!(Pools::pending_rewards(20), Some(50));
assert_eq!(Pools::pending_rewards(30), None);
assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50));
assert_eq!(Pools::api_pending_rewards(20), Some(50));
assert_eq!(Pools::api_pending_rewards(30), None);

Balances::make_free_balance_be(&30, ed + 10);
assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1));

assert_eq!(Pools::pending_rewards(10), Some(30 + 50));
assert_eq!(Pools::pending_rewards(20), Some(50));
assert_eq!(Pools::pending_rewards(30), Some(0));
assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50));
assert_eq!(Pools::api_pending_rewards(20), Some(50));
assert_eq!(Pools::api_pending_rewards(30), Some(0));

Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap();

assert_eq!(Pools::pending_rewards(10), Some(30 + 50 + 20));
assert_eq!(Pools::pending_rewards(20), Some(50 + 20));
assert_eq!(Pools::pending_rewards(30), Some(20));
assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50 + 20));
assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20));
assert_eq!(Pools::api_pending_rewards(30), Some(20));

// 10 should claim 10, 20 should claim nothing.
assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10)));
assert_eq!(Pools::pending_rewards(10), Some(0));
assert_eq!(Pools::pending_rewards(20), Some(50 + 20));
assert_eq!(Pools::pending_rewards(30), Some(20));
assert_eq!(Pools::api_pending_rewards(10), Some(0));
assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20));
assert_eq!(Pools::api_pending_rewards(30), Some(20));

assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20)));
assert_eq!(Pools::pending_rewards(10), Some(0));
assert_eq!(Pools::pending_rewards(20), Some(0));
assert_eq!(Pools::pending_rewards(30), Some(20));
assert_eq!(Pools::api_pending_rewards(10), Some(0));
assert_eq!(Pools::api_pending_rewards(20), Some(0));
assert_eq!(Pools::api_pending_rewards(30), Some(20));

assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30)));
assert_eq!(Pools::pending_rewards(10), Some(0));
assert_eq!(Pools::pending_rewards(20), Some(0));
assert_eq!(Pools::pending_rewards(30), Some(0));
assert_eq!(Pools::api_pending_rewards(10), Some(0));
assert_eq!(Pools::api_pending_rewards(20), Some(0));
assert_eq!(Pools::api_pending_rewards(30), Some(0));
});
}

Expand Down
24 changes: 24 additions & 0 deletions frame/staking/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "pallet-staking-runtime-api"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "RPC runtime API for transaction payment FRAME pallet"
readme = "README.md"

[package.metadata.docs.rs]
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" }

[features]
default = ["std"]
std = [
"codec/std",
"sp-api/std",
]
3 changes: 3 additions & 0 deletions frame/staking/runtime-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Runtime API definition for the staking pallet.

License: Apache-2.0
32 changes: 32 additions & 0 deletions frame/staking/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// This file is part of Substrate.

// Copyright (C) 2023 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Runtime API definition for the staking pallet.
#![cfg_attr(not(feature = "std"), no_std)]

use codec::Codec;

sp_api::decl_runtime_apis! {
pub trait StakingApi<Balance>
where
Balance: Codec,
{
/// Returns the nominations quota for a nominator with a given balance.
fn nominations_quota(balance: Balance) -> u32;
}
}
14 changes: 14 additions & 0 deletions frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,20 @@ impl<T: Config> Pallet<T> {
}
}

impl<T: Config> Pallet<T> {
/// Returns the current nominations quota for nominators.
///
/// Used by the runtime API.
/// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it
/// is redundant. However, with the upcoming changes in
/// <https://github.com/paritytech/substrate/pull/12970>, the nominations quota will change
/// depending on the nominators balance. We're introducing this runtime API now to prepare the
/// community to use it before rolling out PR#12970.
pub fn api_nominations_quota(_balance: BalanceOf<T>) -> u32 {
T::MaxNominations::get()
}
}

impl<T: Config> ElectionDataProvider for Pallet<T> {
type AccountId = T::AccountId;
type BlockNumber = BlockNumberFor<T>;
Expand Down

0 comments on commit cb5cbed

Please sign in to comment.