Skip to content

Commit

Permalink
Impl Staking RPC (paritytech#152)
Browse files Browse the repository at this point in the history
* Impl API for ValidatorInfos

* Cache the treasury account when slashing using struct Slasher

* Return Vec<ValidatorInfo>

* Introduce RpcBalance<Balance>

* Rename to generic U128<Balance>

* Introduce U128<Balance> in xpallet_support

* Add doc about U128<Balance>

* Add RpcValidatorLedger

* Fix session keys initialization

* Add xstaking_getValidatorByAccount

* .
  • Loading branch information
liuchengxu committed Jul 22, 2020
1 parent af6c435 commit 22b1228
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 34 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ fn testnet_genesis(
.map(|x| {
(
x.0.clone(),
x.1.clone(),
x.0.clone(),
session_keys(x.2.clone(), x.3.clone(), x.4.clone()),
)
})
Expand Down
2 changes: 1 addition & 1 deletion rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ where
<Client<BE, E, Block, RA> as ProvideRuntimeApi<Block>>::Api:
xpallet_assets_rpc_runtime_api::AssetsApi<Block, AccountId, Balance>,
<Client<BE, E, Block, RA> as ProvideRuntimeApi<Block>>::Api:
xpallet_mining_staking_rpc_runtime_api::XStakingApi<Block, AccountId>,
xpallet_mining_staking_rpc_runtime_api::XStakingApi<Block, AccountId, Balance, BlockNumber>,
<Client<BE, E, Block, RA> as ProvideRuntimeApi<Block>>::Api:
xpallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber>,
<<Client<BE, E, Block, RA> as ProvideRuntimeApi<Block>>::Api as sp_api::ApiErrorExt>::Error:
Expand Down
2 changes: 2 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ xpallet-mining-staking-rpc-runtime-api = { path = "../xpallets/mining/staking/r
xpallet-mining-asset = { path = "../xpallets/mining/asset", default-features = false }
xpallet-protocol = { path = "../xpallets/protocol", default-features = false }
xpallet-system = { path = "../xpallets/system", default-features = false }
xpallet-support = { path = "../xpallets/support", default-features = false }
xpallet-transaction-payment = { path = "../xpallets/transaction-payment", default-features = false }
xpallet-transaction-payment-rpc-runtime-api = { path = "../xpallets/transaction-payment/rpc/runtime-api", default-features = false }

Expand Down Expand Up @@ -113,6 +114,7 @@ std = [
"xpallet-mining-asset/std",
"xpallet-protocol/std",
"xpallet-system/std",
"xpallet-support/std",
"xpallet-transaction-payment/std",
"xpallet-transaction-payment-rpc-runtime-api/std",
]
7 changes: 5 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,13 @@ impl_runtime_apis! {
}
}

impl xpallet_mining_staking_rpc_runtime_api::XStakingApi<Block, AccountId> for Runtime {
fn validators() -> Vec<AccountId> {
impl xpallet_mining_staking_rpc_runtime_api::XStakingApi<Block, AccountId, Balance, BlockNumber> for Runtime {
fn validators() -> Vec<xpallet_mining_staking::ValidatorInfo<AccountId, xpallet_support::RpcBalance<Balance>, BlockNumber>> {
XStaking::validators_info()
}
fn validator_info_of(who: AccountId) -> xpallet_mining_staking::ValidatorInfo<AccountId, xpallet_support::RpcBalance<Balance>, BlockNumber> {
XStaking::validator_info_of(who)
}
}

impl xpallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber>
Expand Down
2 changes: 2 additions & 0 deletions xpallets/mining/staking/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate.git", tag = "v2
jsonrpc-core = "14.2.0"
jsonrpc-derive = "14.2.1"
jsonrpc-core-client = "14.2.0"
xpallet-mining-staking = { path = "../" }
xpallet-mining-staking-rpc-runtime-api = { path = "./runtime-api" }
xpallet-support = { path = "../../../support" }
6 changes: 6 additions & 0 deletions xpallets/mining/staking/rpc/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ codec = { package = "parity-scale-codec", version = "1.3.1", default-features =
sp-api = { git = "https://github.com/paritytech/substrate.git", tag = "v2.0.0-rc4", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate.git", tag = "v2.0.0-rc4", default-features = false }

xpallet-mining-staking = { path = "../..", default-features = false }
xpallet-support = { path = "../../../../support", default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"sp-api/std",
"sp-std/std",

"xpallet-mining-staking/std",
"xpallet-support/std",
]
16 changes: 12 additions & 4 deletions xpallets/mining/staking/rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

#![cfg_attr(not(feature = "std"), no_std)]

use codec::Codec;
use sp_std::prelude::*;
use xpallet_mining_staking::ValidatorInfo;
use xpallet_support::RpcBalance;

sp_api::decl_runtime_apis! {
/// The API to query account nonce (aka transaction index).
pub trait XStakingApi<AccountId> where
AccountId: codec::Codec,
pub trait XStakingApi<AccountId, Balance, BlockNumber> where
AccountId: Codec,
Balance: Codec,
BlockNumber: Codec,
{
/// Get all potential validators.
fn validators() -> Vec<AccountId>;
/// Get overall information about all potential validators.
fn validators() -> Vec<ValidatorInfo<AccountId, RpcBalance<Balance>, BlockNumber>>;

/// Get overall information given the validator AccountId.
fn validator_info_of(who: AccountId) -> ValidatorInfo<AccountId, RpcBalance<Balance>, BlockNumber>;
}
}
56 changes: 41 additions & 15 deletions xpallets/mining/staking/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,27 @@ use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use std::sync::Arc;
use xpallet_mining_staking::ValidatorInfo;
use xpallet_mining_staking_rpc_runtime_api::XStakingApi as XStakingRuntimeApi;
use xpallet_support::RpcBalance;

/// XStaking RPC methods.
#[rpc]
pub trait XStakingApi<BlockHash, AccountId> {
/// Executes a call to a contract.
///
/// This call is performed locally without submitting any transactions. Thus executing this
/// won't change any state. Nonetheless, the calling state-changing contracts is still possible.
///
/// This method is useful for calling getter-like methods on contracts.
pub trait XStakingApi<BlockHash, AccountId, RpcBalance, BlockNumber> {
/// Get overall information about all potential validators
#[rpc(name = "xstaking_getValidators")]
fn validators(&self, at: Option<BlockHash>) -> Result<Vec<AccountId>>;
fn validators(
&self,
at: Option<BlockHash>,
) -> Result<Vec<ValidatorInfo<AccountId, RpcBalance, BlockNumber>>>;

/// Get overall information given the validator AccountId.
#[rpc(name = "xstaking_getValidatorByAccount")]
fn validator_info_of(
&self,
who: AccountId,
at: Option<BlockHash>,
) -> Result<ValidatorInfo<AccountId, RpcBalance, BlockNumber>>;
}

/// A struct that implements the [`XStakingApi`].
Expand All @@ -38,24 +46,42 @@ impl<C, B> XStaking<C, B> {
}
}

impl<C, Block, AccountId> XStakingApi<<Block as BlockT>::Hash, AccountId> for XStaking<C, Block>
impl<C, Block, AccountId, Balance, BlockNumber>
XStakingApi<<Block as BlockT>::Hash, AccountId, RpcBalance<Balance>, BlockNumber>
for XStaking<C, Block>
where
Block: BlockT,
C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
C::Api: XStakingRuntimeApi<Block, AccountId>,
C::Api: XStakingRuntimeApi<Block, AccountId, Balance, BlockNumber>,
AccountId: Codec,
Balance: Codec,
BlockNumber: Codec,
{
fn validators(&self, at: Option<<Block as BlockT>::Hash>) -> Result<Vec<AccountId>> {
fn validators(
&self,
at: Option<<Block as BlockT>::Hash>,
) -> Result<Vec<ValidatorInfo<AccountId, RpcBalance<Balance>, BlockNumber>>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash));

let result = api
.validators(&at)
.map_err(|e| runtime_error_into_rpc_err(e))?;
Ok(api.validators(&at).map_err(runtime_error_into_rpc_err)?)
}

fn validator_info_of(
&self,
who: AccountId,
at: Option<<Block as BlockT>::Hash>,
) -> Result<ValidatorInfo<AccountId, RpcBalance<Balance>, BlockNumber>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash));

Ok(result)
Ok(api
.validator_info_of(&at, who)
.map_err(runtime_error_into_rpc_err)?)
}
}

Expand Down
30 changes: 27 additions & 3 deletions xpallets/mining/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use xp_mining_common::{
};
use xp_mining_staking::{AssetMining, SessionIndex, TreasuryAccount, UnbondedIndex};
use xpallet_assets::{AssetErr, AssetType};
use xpallet_support::debug;
use xpallet_support::{debug, RpcBalance};

pub use impls::{IdentificationTuple, SimpleValidatorRewardPotAccountDeterminer};
pub use types::*;
Expand Down Expand Up @@ -733,7 +733,31 @@ impl<T: Trait> Module<T> {
}

impl<T: Trait> Module<T> {
pub fn validators_info() -> Vec<T::AccountId> {
Self::validator_set().collect()
pub fn validators_info(
) -> Vec<ValidatorInfo<T::AccountId, RpcBalance<T::Balance>, T::BlockNumber>> {
Self::validator_set().map(Self::validator_info_of).collect()
}

pub fn validator_info_of(
who: T::AccountId,
) -> ValidatorInfo<T::AccountId, RpcBalance<T::Balance>, T::BlockNumber> {
let profile = Validators::<T>::get(&who);
let ledger: RpcValidatorLedger<RpcBalance<T::Balance>, T::BlockNumber> =
ValidatorLedgers::<T>::get(&who).into();
let self_bonded: RpcBalance<T::Balance> =
Nominations::<T>::get(&who, &who).nomination.into();
let is_validating = T::SessionInterface::validators().contains(&who);
let reward_pot_account = T::DetermineRewardPotAccount::reward_pot_account_for(&who);
let reward_pot_balance: RpcBalance<T::Balance> =
xpallet_assets::Module::<T>::pcx_free_balance(&reward_pot_account).into();
ValidatorInfo {
account: who,
profile,
ledger,
is_validating,
self_bonded,
reward_pot_account,
reward_pot_balance,
}
}
}
57 changes: 49 additions & 8 deletions xpallets/mining/staking/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use sp_runtime::RuntimeDebug;
use sp_runtime::{Deserialize, Serialize};
use xp_mining_common::WeightType;
use xp_mining_staking::MiningPower;
use xpallet_support::RpcWeightType;

/// Destination for minted fresh PCX on each new session.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
Expand Down Expand Up @@ -51,6 +52,33 @@ pub struct ValidatorLedger<Balance, BlockNumber> {
pub last_total_vote_weight_update: BlockNumber,
}

/// Vote weight properties of validator.
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct RpcValidatorLedger<RpcBalance, BlockNumber> {
/// The total amount of all the nominators' vote balances.
pub total: RpcBalance,
/// Last calculated total vote weight of current validator.
pub last_total_vote_weight: RpcWeightType,
/// Block number at which point `last_total_vote_weight` just updated.
pub last_total_vote_weight_update: BlockNumber,
}

impl<Balance, BlockNumber> From<ValidatorLedger<Balance, BlockNumber>>
for RpcValidatorLedger<RpcBalance<Balance>, BlockNumber>
{
fn from(ledger: ValidatorLedger<Balance, BlockNumber>) -> Self {
let last_total_vote_weight: RpcWeightType = ledger.last_total_vote_weight.into();
let total: RpcBalance<Balance> = ledger.total.into();
Self {
total,
last_total_vote_weight,
last_total_vote_weight_update: ledger.last_total_vote_weight_update,
}
}
}

/// Vote weight properties of nominator.
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
pub struct NominatorLedger<Balance, BlockNumber> {
Expand All @@ -62,6 +90,17 @@ pub struct NominatorLedger<Balance, BlockNumber> {
pub last_vote_weight_update: BlockNumber,
}

/// Vote weight properties of nominator.
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
pub struct RpcNominatorLedger<Balance, BlockNumber> {
/// The amount of
pub nomination: Balance,
/// Last calculated total vote weight of current nominator.
pub last_vote_weight: RpcWeightType,
/// Block number at which point `last_vote_weight` just updated.
pub last_vote_weight_update: BlockNumber,
}

/// Profile of staking validator.
///
/// These fields are static or updated less frequently.
Expand Down Expand Up @@ -90,24 +129,25 @@ pub struct NominatorProfile<Balance, BlockNumber> {
pub unbonded_chunks: Vec<Unbonded<Balance, BlockNumber>>,
}

#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)]
/// Total information about a validator.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct ValidatorInfo<AccountId, Balance, BlockNumber> {
pub struct ValidatorInfo<AccountId, RpcBalance, BlockNumber> {
/// AccountId of this (potential) validator.
pub account: AccountId,
#[cfg_attr(feature = "std", serde(flatten))]
pub profile: ValidatorProfile<BlockNumber>,
#[cfg_attr(feature = "std", serde(flatten))]
pub ledger: ValidatorLedger<Balance, BlockNumber>,
/// Being a validator, reponsible for authoring the new blocks.
pub ledger: RpcValidatorLedger<RpcBalance, BlockNumber>,
/// Being a validator, responsible for authoring the new blocks.
pub is_validating: bool,
/// How much balances the validator has bonded itself.
pub self_bonded: Balance,
pub self_bonded: RpcBalance,
/// AccountId of the reward pot of this validator.
pub reward_pot_account: AccountId,
/// Balance of the reward pot account.
pub reward_pot_balance: Balance,
pub reward_pot_balance: RpcBalance,
}

/// Information regarding the active era (era in used in session).
Expand Down Expand Up @@ -142,7 +182,7 @@ impl Default for Forcing {
}
}

// Top level shares of various reward destinations.
/// Top level shares of various reward destinations.
#[derive(Copy, Clone, PartialEq, Eq, Default, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct GlobalDistribution {
Expand All @@ -153,6 +193,7 @@ pub struct GlobalDistribution {
impl GlobalDistribution {
/// Calculates the rewards for treasury and mining accordingly.
pub fn calc_rewards<T: Trait>(&self, reward: T::Balance) -> (T::Balance, T::Balance) {
assert!(self.treasury + self.mining > 0);
let treasury_reward = reward * self.treasury.saturated_into()
/ (self.treasury + self.mining).saturated_into();
(treasury_reward, reward - treasury_reward)
Expand Down Expand Up @@ -212,7 +253,7 @@ impl MiningDistribution {
} else {
assert!(
m2 > 0,
"cross_mining_shares is ensured to be positive in set_distribution_ratio()"
"asset_mining_shares is ensured to be positive in set_distribution_ratio()"
);
// There could be some computation loss here, but it's ok.
let treasury_extra = (m2 - m1) * asset_mining_reward_cap.saturated_into::<u128>() / m2;
Expand Down
Loading

0 comments on commit 22b1228

Please sign in to comment.