mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 07:41:08 +00:00
Refactor CurrencyToVote (#6896)
* Refactor CurrencyToVote to avoid calls to total_issuance. * Update frame/support/src/traits.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Some grumbles * Fix last grumbles. * Fix comment * Final fix Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -17,8 +17,6 @@
|
||||
|
||||
//! Some configurable implementations as associated type for the substrate runtime.
|
||||
|
||||
use node_primitives::Balance;
|
||||
use sp_runtime::traits::Convert;
|
||||
use frame_support::traits::{OnUnbalanced, Currency};
|
||||
use crate::{Balances, Authorship, NegativeImbalance};
|
||||
|
||||
@@ -29,26 +27,9 @@ impl OnUnbalanced<NegativeImbalance> for Author {
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct that handles the conversion of Balance -> `u64`. This is used for staking's election
|
||||
/// calculation.
|
||||
pub struct CurrencyToVoteHandler;
|
||||
|
||||
impl CurrencyToVoteHandler {
|
||||
fn factor() -> Balance { (Balances::total_issuance() / u64::max_value() as Balance).max(1) }
|
||||
}
|
||||
|
||||
impl Convert<Balance, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: Balance) -> u64 { (x / Self::factor()) as u64 }
|
||||
}
|
||||
|
||||
impl Convert<u128, Balance> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> Balance { x * Self::factor() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod multiplier_tests {
|
||||
use super::*;
|
||||
use sp_runtime::{assert_eq_error_rate, FixedPointNumber};
|
||||
use sp_runtime::{assert_eq_error_rate, FixedPointNumber, traits::Convert};
|
||||
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -30,7 +30,10 @@ use frame_support::{
|
||||
Weight, IdentityFee,
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
},
|
||||
traits::{Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier},
|
||||
traits::{
|
||||
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier,
|
||||
U128CurrencyToVote,
|
||||
},
|
||||
};
|
||||
use frame_system::{EnsureRoot, EnsureOneOf};
|
||||
use frame_support::traits::InstanceFilter;
|
||||
@@ -78,7 +81,7 @@ pub use pallet_staking::StakerStatus;
|
||||
|
||||
/// Implementations of some helper traits passed into runtime modules as associated types.
|
||||
pub mod impls;
|
||||
use impls::{CurrencyToVoteHandler, Author};
|
||||
use impls::Author;
|
||||
|
||||
/// Constant values used within the runtime.
|
||||
pub mod constants;
|
||||
@@ -448,7 +451,7 @@ parameter_types! {
|
||||
impl pallet_staking::Trait for Runtime {
|
||||
type Currency = Balances;
|
||||
type UnixTime = Timestamp;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = U128CurrencyToVote;
|
||||
type RewardRemainder = Treasury;
|
||||
type Event = Event;
|
||||
type Slash = Treasury; // send the slashed funds to the treasury.
|
||||
@@ -574,7 +577,7 @@ impl pallet_elections_phragmen::Trait for Runtime {
|
||||
// NOTE: this implies that council's genesis members cannot be set directly and must come from
|
||||
// this module.
|
||||
type InitializeMembers = Council;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = U128CurrencyToVote;
|
||||
type CandidacyBond = CandidacyBond;
|
||||
type VotingBond = VotingBond;
|
||||
type LoserCandidate = ();
|
||||
|
||||
@@ -23,7 +23,7 @@ use sp_runtime::{
|
||||
Perbill, impl_opaque_keys,
|
||||
curve::PiecewiseLinear,
|
||||
testing::{Digest, DigestItem, Header, TestXt,},
|
||||
traits::{Convert, Header as _, IdentityLookup, OpaqueKeys, SaturatedConversion},
|
||||
traits::{Header as _, IdentityLookup, OpaqueKeys},
|
||||
};
|
||||
use frame_system::InitKind;
|
||||
use frame_support::{
|
||||
@@ -183,23 +183,9 @@ parameter_types! {
|
||||
pub const StakingUnsignedPriority: u64 = u64::max_value() / 2;
|
||||
}
|
||||
|
||||
pub struct CurrencyToVoteHandler;
|
||||
|
||||
impl Convert<u128, u128> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u128 {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_staking::Trait for Test {
|
||||
type RewardRemainder = ();
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type Event = ();
|
||||
type Currency = Balances;
|
||||
type Slash = ();
|
||||
|
||||
@@ -83,25 +83,26 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::prelude::*;
|
||||
use sp_runtime::{
|
||||
DispatchError, RuntimeDebug, Perbill,
|
||||
traits::{Zero, StaticLookup, Convert, Saturating},
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
decl_storage, decl_event, ensure, decl_module, decl_error,
|
||||
weights::Weight,
|
||||
storage::{StorageMap, IterableStorageMap},
|
||||
decl_error, decl_event, decl_module, decl_storage,
|
||||
dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo},
|
||||
ensure,
|
||||
storage::{IterableStorageMap, StorageMap},
|
||||
traits::{
|
||||
Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons,
|
||||
ChangeMembers, OnUnbalanced, WithdrawReason, Contains, InitializeMembers, BalanceStatus,
|
||||
ContainsLengthBound,
|
||||
}
|
||||
BalanceStatus, ChangeMembers, Contains, ContainsLengthBound, Currency, CurrencyToVote, Get,
|
||||
InitializeMembers, LockIdentifier, LockableCurrency, OnUnbalanced, ReservableCurrency,
|
||||
WithdrawReason, WithdrawReasons,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_npos_elections::{ExtendedBalance, VoteWeight, ElectionResult};
|
||||
use frame_system::{ensure_signed, ensure_root};
|
||||
use frame_system::{ensure_root, ensure_signed};
|
||||
use sp_npos_elections::{ElectionResult, ExtendedBalance};
|
||||
use sp_runtime::{
|
||||
traits::{Saturating, StaticLookup, Zero},
|
||||
DispatchError, Perbill, RuntimeDebug,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
mod benchmarking;
|
||||
mod default_weights;
|
||||
@@ -172,7 +173,7 @@ pub trait Trait: frame_system::Trait {
|
||||
|
||||
/// Convert a balance into a number used for election calculation.
|
||||
/// This must fit into a `u64` but is allowed to be sensibly lossy.
|
||||
type CurrencyToVote: Convert<BalanceOf<Self>, VoteWeight> + Convert<ExtendedBalance, BalanceOf<Self>>;
|
||||
type CurrencyToVote: CurrencyToVote<BalanceOf<Self>>;
|
||||
|
||||
/// How much should be locked up in order to submit one's candidacy.
|
||||
type CandidacyBond: Get<BalanceOf<Self>>;
|
||||
@@ -871,16 +872,13 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
|
||||
// helper closures to deal with balance/stake.
|
||||
let to_votes = |b: BalanceOf<T>| -> VoteWeight {
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, VoteWeight>>::convert(b)
|
||||
};
|
||||
let to_balance = |e: ExtendedBalance| -> BalanceOf<T> {
|
||||
<T::CurrencyToVote as Convert<ExtendedBalance, BalanceOf<T>>>::convert(e)
|
||||
};
|
||||
let total_issuance = T::Currency::total_issuance();
|
||||
let to_votes = |b: BalanceOf<T>| T::CurrencyToVote::to_vote(b, total_issuance);
|
||||
let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance);
|
||||
|
||||
// used for prime election.
|
||||
let voters_and_stakes = Voting::<T>::iter()
|
||||
.map(|(voter, (stake, votes))| { (voter, stake, votes) })
|
||||
.map(|(voter, (stake, votes))| (voter, stake, votes))
|
||||
.collect::<Vec<_>>();
|
||||
// used for phragmen.
|
||||
let voters_and_votes = voters_and_stakes.iter()
|
||||
@@ -1186,17 +1184,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple structure that exposes how u64 currency can be represented as... u64.
|
||||
pub struct CurrencyToVoteHandler;
|
||||
impl Convert<u64, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u64) -> u64 { x }
|
||||
}
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x as u64
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types!{
|
||||
pub const ElectionsPhragmenModuleId: LockIdentifier = *b"phrelect";
|
||||
}
|
||||
@@ -1205,7 +1192,7 @@ mod tests {
|
||||
type ModuleId = ElectionsPhragmenModuleId;
|
||||
type Event = Event;
|
||||
type Currency = Balances;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type ChangeMembers = TestChangeMembers;
|
||||
type InitializeMembers = ();
|
||||
type CandidacyBond = CandidacyBond;
|
||||
|
||||
@@ -36,7 +36,7 @@ use sp_runtime::{
|
||||
curve::PiecewiseLinear,
|
||||
impl_opaque_keys,
|
||||
testing::{Header, TestXt, UintAuthorityId},
|
||||
traits::{Convert, IdentityLookup, OpaqueKeys, SaturatedConversion},
|
||||
traits::{IdentityLookup, OpaqueKeys},
|
||||
DigestItem, Perbill,
|
||||
};
|
||||
use sp_staking::SessionIndex;
|
||||
@@ -198,23 +198,9 @@ parameter_types! {
|
||||
pub const StakingUnsignedPriority: u64 = u64::max_value() / 2;
|
||||
}
|
||||
|
||||
pub struct CurrencyToVoteHandler;
|
||||
|
||||
impl Convert<u128, u128> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u128 {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_staking::Trait for Test {
|
||||
type RewardRemainder = ();
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type Event = TestEvent;
|
||||
type Currency = Balances;
|
||||
type Slash = ();
|
||||
|
||||
@@ -26,7 +26,6 @@ use frame_support::{
|
||||
};
|
||||
use frame_system as system;
|
||||
use sp_runtime::{
|
||||
SaturatedConversion,
|
||||
traits::{IdentityLookup, Block as BlockT},
|
||||
testing::{Header, UintAuthorityId},
|
||||
};
|
||||
@@ -150,22 +149,10 @@ parameter_types! {
|
||||
|
||||
pub type Extrinsic = sp_runtime::testing::TestXt<Call, ()>;
|
||||
|
||||
pub struct CurrencyToVoteHandler;
|
||||
impl Convert<u64, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u64) -> u64 {
|
||||
x
|
||||
}
|
||||
}
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_staking::Trait for Test {
|
||||
type Currency = Balances;
|
||||
type UnixTime = pallet_timestamp::Module<Self>;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type RewardRemainder = ();
|
||||
type Event = Event;
|
||||
type Slash = ();
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use sp_runtime::traits::{Convert, SaturatedConversion, IdentityLookup};
|
||||
use sp_runtime::traits::IdentityLookup;
|
||||
use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types};
|
||||
|
||||
type AccountId = u64;
|
||||
@@ -42,18 +42,6 @@ impl_outer_dispatch! {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CurrencyToVoteHandler;
|
||||
impl Convert<u64, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u64) -> u64 {
|
||||
x
|
||||
}
|
||||
}
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct Test;
|
||||
|
||||
@@ -172,7 +160,7 @@ impl<C> frame_system::offchain::SendTransactionTypes<C> for Test where
|
||||
impl pallet_staking::Trait for Test {
|
||||
type Currency = Balances;
|
||||
type UnixTime = pallet_timestamp::Module<Self>;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type RewardRemainder = ();
|
||||
type Event = ();
|
||||
type Slash = ();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
//! Mock file for staking fuzzing.
|
||||
|
||||
use sp_runtime::traits::{Convert, SaturatedConversion};
|
||||
use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types};
|
||||
|
||||
type AccountId = u64;
|
||||
@@ -41,18 +40,6 @@ impl_outer_dispatch! {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CurrencyToVoteHandler;
|
||||
impl Convert<u64, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u64) -> u64 {
|
||||
x
|
||||
}
|
||||
}
|
||||
impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct Test;
|
||||
|
||||
@@ -177,7 +164,7 @@ impl<C> frame_system::offchain::SendTransactionTypes<C> for Test where
|
||||
impl pallet_staking::Trait for Test {
|
||||
type Currency = Balances;
|
||||
type UnixTime = pallet_timestamp::Module<Self>;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type RewardRemainder = ();
|
||||
type Event = ();
|
||||
type Slash = ();
|
||||
|
||||
@@ -299,7 +299,7 @@ use frame_support::{
|
||||
},
|
||||
traits::{
|
||||
Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get,
|
||||
UnixTime, EstimateNextNewSession, EnsureOrigin,
|
||||
UnixTime, EstimateNextNewSession, EnsureOrigin, CurrencyToVote,
|
||||
}
|
||||
};
|
||||
use pallet_session::historical;
|
||||
@@ -811,7 +811,7 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes<Call<Self>> {
|
||||
/// [`sp_npos_elections`] crate which accepts u64 numbers and does operations in 128.
|
||||
/// Consequently, the backward convert is used convert the u128s from sp-elections back to a
|
||||
/// [`BalanceOf`].
|
||||
type CurrencyToVote: Convert<BalanceOf<Self>, VoteWeight> + Convert<u128, BalanceOf<Self>>;
|
||||
type CurrencyToVote: CurrencyToVote<BalanceOf<Self>>;
|
||||
|
||||
/// Tokens have been minted and are unused for validator-reward.
|
||||
/// See [Era payout](./index.html#era-payout).
|
||||
@@ -2192,11 +2192,22 @@ impl<T: Trait> Module<T> {
|
||||
Self::bonded(stash).and_then(Self::ledger).map(|l| l.active).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// internal impl of [`slashable_balance_of`] that returns [`VoteWeight`].
|
||||
pub fn slashable_balance_of_vote_weight(stash: &T::AccountId) -> VoteWeight {
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, VoteWeight>>::convert(
|
||||
Self::slashable_balance_of(stash)
|
||||
)
|
||||
/// Internal impl of [`slashable_balance_of`] that returns [`VoteWeight`].
|
||||
pub fn slashable_balance_of_vote_weight(stash: &T::AccountId, issuance: BalanceOf<T>) -> VoteWeight {
|
||||
T::CurrencyToVote::to_vote(Self::slashable_balance_of(stash), issuance)
|
||||
}
|
||||
|
||||
/// Returns a closure around `slashable_balance_of_vote_weight` that can be passed around.
|
||||
///
|
||||
/// This prevents call sites from repeatedly requesting `total_issuance` from backend. But it is
|
||||
/// important to be only used while the total issuance is not changing.
|
||||
pub fn slashable_balance_of_fn() -> Box<dyn Fn(&T::AccountId) -> VoteWeight> {
|
||||
// NOTE: changing this to unboxed `impl Fn(..)` return type and the module will still
|
||||
// compile, while some types in mock fail to resolve.
|
||||
let issuance = T::Currency::total_issuance();
|
||||
Box::new(move |who: &T::AccountId| -> VoteWeight {
|
||||
Self::slashable_balance_of_vote_weight(who, issuance)
|
||||
})
|
||||
}
|
||||
|
||||
/// Dump the list of validators and nominators into vectors and keep them on-chain.
|
||||
@@ -2601,7 +2612,7 @@ impl<T: Trait> Module<T> {
|
||||
// convert into staked assignments.
|
||||
let staked_assignments = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
Self::slashable_balance_of_vote_weight,
|
||||
Self::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
// build the support map thereof in order to evaluate.
|
||||
@@ -2852,7 +2863,7 @@ impl<T: Trait> Module<T> {
|
||||
/// `PrimitiveElectionResult` into `ElectionResult`.
|
||||
///
|
||||
/// No storage item is updated.
|
||||
fn do_on_chain_phragmen() -> Option<ElectionResult<T::AccountId, BalanceOf<T>>> {
|
||||
pub fn do_on_chain_phragmen() -> Option<ElectionResult<T::AccountId, BalanceOf<T>>> {
|
||||
if let Some(phragmen_result) = Self::do_phragmen::<ChainAccuracy>(0) {
|
||||
let elected_stashes = phragmen_result.winners.iter()
|
||||
.map(|(s, _)| s.clone())
|
||||
@@ -2861,7 +2872,7 @@ impl<T: Trait> Module<T> {
|
||||
|
||||
let staked_assignments = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
Self::slashable_balance_of_vote_weight,
|
||||
Self::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let supports = build_support_map::<T::AccountId>(
|
||||
@@ -2903,16 +2914,16 @@ impl<T: Trait> Module<T> {
|
||||
/// Self votes are added and nominations before the most recent slashing span are ignored.
|
||||
///
|
||||
/// No storage item is updated.
|
||||
pub fn do_phragmen<Accuracy: PerThing>(
|
||||
iterations: usize,
|
||||
) -> Option<PrimitiveElectionResult<T::AccountId, Accuracy>>
|
||||
pub fn do_phragmen<Accuracy: PerThing>(iterations: usize)
|
||||
-> Option<PrimitiveElectionResult<T::AccountId, Accuracy>>
|
||||
where ExtendedBalance: From<InnerOf<Accuracy>>
|
||||
{
|
||||
let weight_of = Self::slashable_balance_of_fn();
|
||||
let mut all_nominators: Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)> = Vec::new();
|
||||
let mut all_validators = Vec::new();
|
||||
for (validator, _) in <Validators<T>>::iter() {
|
||||
// append self vote
|
||||
let self_vote = (validator.clone(), Self::slashable_balance_of_vote_weight(&validator), vec![validator.clone()]);
|
||||
let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]);
|
||||
all_nominators.push(self_vote);
|
||||
all_validators.push(validator);
|
||||
}
|
||||
@@ -2932,7 +2943,7 @@ impl<T: Trait> Module<T> {
|
||||
(nominator, targets)
|
||||
});
|
||||
all_nominators.extend(nominator_votes.map(|(n, ns)| {
|
||||
let s = Self::slashable_balance_of_vote_weight(&n);
|
||||
let s = weight_of(&n);
|
||||
(n, s, ns)
|
||||
}));
|
||||
|
||||
@@ -2956,8 +2967,8 @@ impl<T: Trait> Module<T> {
|
||||
fn collect_exposure(
|
||||
supports: SupportMap<T::AccountId>,
|
||||
) -> Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)> {
|
||||
let to_balance = |e: ExtendedBalance|
|
||||
<T::CurrencyToVote as Convert<ExtendedBalance, BalanceOf<T>>>::convert(e);
|
||||
let total_issuance = T::Currency::total_issuance();
|
||||
let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance);
|
||||
|
||||
supports.into_iter().map(|(validator, support)| {
|
||||
// build `struct exposure` from `support`
|
||||
@@ -2966,7 +2977,7 @@ impl<T: Trait> Module<T> {
|
||||
let mut total: BalanceOf<T> = Zero::zero();
|
||||
support.voters
|
||||
.into_iter()
|
||||
.map(|(nominator, weight)| (nominator, to_balance(weight)))
|
||||
.map(|(nominator, weight)| (nominator, to_currency(weight)))
|
||||
.for_each(|(nominator, stake)| {
|
||||
if nominator == validator {
|
||||
own = own.saturating_add(stake);
|
||||
|
||||
@@ -27,18 +27,14 @@ use frame_support::{
|
||||
use sp_core::H256;
|
||||
use sp_io;
|
||||
use sp_npos_elections::{
|
||||
build_support_map, evaluate_support, reduce, ElectionScore, ExtendedBalance, StakedAssignment,
|
||||
build_support_map, evaluate_support, reduce, ExtendedBalance, StakedAssignment, ElectionScore,
|
||||
};
|
||||
use sp_runtime::{
|
||||
curve::PiecewiseLinear,
|
||||
testing::{Header, TestXt, UintAuthorityId},
|
||||
traits::{Convert, IdentityLookup, SaturatedConversion, Zero},
|
||||
Perbill,
|
||||
};
|
||||
use sp_staking::{
|
||||
offence::{OffenceDetails, OnOffenceHandler},
|
||||
SessionIndex,
|
||||
traits::{IdentityLookup, Zero},
|
||||
};
|
||||
use sp_staking::offence::{OffenceDetails, OnOffenceHandler};
|
||||
use std::{cell::RefCell, collections::HashSet};
|
||||
|
||||
pub const INIT_TIMESTAMP: u64 = 30_000;
|
||||
@@ -49,19 +45,6 @@ pub(crate) type AccountIndex = u64;
|
||||
pub(crate) type BlockNumber = u64;
|
||||
pub(crate) type Balance = u128;
|
||||
|
||||
/// Simple structure that exposes how u64 currency can be represented as... u64.
|
||||
pub struct CurrencyToVoteHandler;
|
||||
impl Convert<Balance, u64> for CurrencyToVoteHandler {
|
||||
fn convert(x: Balance) -> u64 {
|
||||
x.saturated_into()
|
||||
}
|
||||
}
|
||||
impl Convert<u128, Balance> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> Balance {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static SESSION: RefCell<(Vec<AccountId>, HashSet<AccountId>)> = RefCell::new(Default::default());
|
||||
static SESSION_PER_ERA: RefCell<SessionIndex> = RefCell::new(3);
|
||||
@@ -319,7 +302,7 @@ impl OnUnbalanced<NegativeImbalanceOf<Test>> for RewardRemainderMock {
|
||||
impl Trait for Test {
|
||||
type Currency = Balances;
|
||||
type UnixTime = Timestamp;
|
||||
type CurrencyToVote = CurrencyToVoteHandler;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type RewardRemainder = RewardRemainderMock;
|
||||
type Event = MetaEvent;
|
||||
type Slash = ();
|
||||
@@ -926,7 +909,7 @@ pub(crate) fn prepare_submission_with(
|
||||
|
||||
let mut staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
Staking::slashable_balance_of_vote_weight,
|
||||
Staking::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
// apply custom tweaks. awesome for testing.
|
||||
@@ -964,7 +947,7 @@ pub(crate) fn prepare_submission_with(
|
||||
let score = if compute_real_score {
|
||||
let staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments_reduced.clone(),
|
||||
Staking::slashable_balance_of_vote_weight,
|
||||
Staking::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map = build_support_map::<AccountId>(
|
||||
@@ -978,10 +961,8 @@ pub(crate) fn prepare_submission_with(
|
||||
|
||||
let compact =
|
||||
CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index)
|
||||
.map_err(|e| { println!("error in compact: {:?}", e); e })
|
||||
.expect("Failed to create compact");
|
||||
|
||||
|
||||
// winner ids to index
|
||||
let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::<Vec<_>>();
|
||||
|
||||
|
||||
@@ -268,13 +268,9 @@ where
|
||||
match compact.len().checked_sub(maximum_allowed_voters as usize) {
|
||||
Some(to_remove) if to_remove > 0 => {
|
||||
// grab all voters and sort them by least stake.
|
||||
let balance_of = <Module<T>>::slashable_balance_of_fn();
|
||||
let mut voters_sorted = <Nominators<T>>::iter()
|
||||
.map(|(who, _)| {
|
||||
(
|
||||
who.clone(),
|
||||
<Module<T>>::slashable_balance_of_vote_weight(&who),
|
||||
)
|
||||
})
|
||||
.map(|(who, _)| (who.clone(), balance_of(&who)))
|
||||
.collect::<Vec<_>>();
|
||||
voters_sorted.sort_by_key(|(_, y)| *y);
|
||||
|
||||
@@ -378,7 +374,7 @@ where
|
||||
// convert into absolute value and to obtain the reduced version.
|
||||
let mut staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
<Module<T>>::slashable_balance_of_vote_weight,
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
// reduce
|
||||
@@ -423,8 +419,8 @@ where
|
||||
let compact = compact.clone();
|
||||
let assignments = compact.into_assignment(nominator_at, validator_at).unwrap();
|
||||
let staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
<Module<T>>::slashable_balance_of_vote_weight,
|
||||
assignments.clone(),
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map = build_support_map::<T::AccountId>(&winners, &staked)
|
||||
|
||||
@@ -193,9 +193,10 @@ pub fn get_weak_solution<T: Trait>(
|
||||
who: w.clone(),
|
||||
distribution: vec![(
|
||||
w.clone(),
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, u64>>::convert(
|
||||
<Module<T>>::slashable_balance_of(&w),
|
||||
) as ExtendedBalance,
|
||||
<Module<T>>::slashable_balance_of_vote_weight(
|
||||
&w,
|
||||
T::Currency::total_issuance(),
|
||||
).into(),
|
||||
)],
|
||||
})
|
||||
});
|
||||
@@ -220,11 +221,6 @@ pub fn get_weak_solution<T: Trait>(
|
||||
.position(|x| x == a)
|
||||
.and_then(|i| <usize as TryInto<ValidatorIndex>>::try_into(i).ok())
|
||||
};
|
||||
let stake_of = |who: &T::AccountId| -> VoteWeight {
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, u64>>::convert(
|
||||
<Module<T>>::slashable_balance_of(who),
|
||||
)
|
||||
};
|
||||
|
||||
// convert back to ratio assignment. This takes less space.
|
||||
let low_accuracy_assignment = assignment_staked_to_ratio_normalized(staked_assignments)
|
||||
@@ -234,7 +230,7 @@ pub fn get_weak_solution<T: Trait>(
|
||||
let score = {
|
||||
let staked = assignment_ratio_to_staked::<_, OffchainAccuracy, _>(
|
||||
low_accuracy_assignment.clone(),
|
||||
stake_of
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map = build_support_map::<T::AccountId>(
|
||||
@@ -325,7 +321,7 @@ pub fn get_single_winner_solution<T: Trait>(
|
||||
|
||||
let stake = <Staking<T>>::slashable_balance_of(&winner);
|
||||
let stake =
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, VoteWeight>>::convert(stake) as ExtendedBalance;
|
||||
<T::CurrencyToVote>::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance;
|
||||
|
||||
let val_index = val_index as ValidatorIndex;
|
||||
let nom_index = nom_index as NominatorIndex;
|
||||
|
||||
@@ -23,9 +23,11 @@ use sp_std::{prelude::*, result, marker::PhantomData, ops::Div, fmt::Debug};
|
||||
use codec::{FullCodec, Codec, Encode, Decode, EncodeLike};
|
||||
use sp_core::u32_trait::Value as U32;
|
||||
use sp_runtime::{
|
||||
RuntimeDebug, ConsensusEngineId, DispatchResult, DispatchError, traits::{
|
||||
RuntimeDebug, ConsensusEngineId, DispatchResult, DispatchError,
|
||||
traits::{
|
||||
MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput, Bounded, Zero,
|
||||
BadOrigin, AtLeast32BitUnsigned
|
||||
BadOrigin, AtLeast32BitUnsigned, UniqueSaturatedFrom, UniqueSaturatedInto,
|
||||
SaturatedConversion,
|
||||
},
|
||||
};
|
||||
use crate::dispatch::Parameter;
|
||||
@@ -1710,6 +1712,73 @@ pub trait Instance: 'static {
|
||||
const PREFIX: &'static str ;
|
||||
}
|
||||
|
||||
/// A trait similar to `Convert` to convert values from `B` an abstract balance type
|
||||
/// into u64 and back from u128. (This conversion is used in election and other places where complex
|
||||
/// calculation over balance type is needed)
|
||||
///
|
||||
/// Total issuance of the currency is passed in, but an implementation of this trait may or may not
|
||||
/// use it.
|
||||
///
|
||||
/// # WARNING
|
||||
///
|
||||
/// the total issuance being passed in implies that the implementation must be aware of the fact
|
||||
/// that its values can affect the outcome. This implies that if the vote value is dependent on the
|
||||
/// total issuance, it should never ber written to storage for later re-use.
|
||||
pub trait CurrencyToVote<B> {
|
||||
/// Convert balance to u64.
|
||||
fn to_vote(value: B, issuance: B) -> u64;
|
||||
|
||||
/// Convert u128 to balance.
|
||||
fn to_currency(value: u128, issuance: B) -> B;
|
||||
}
|
||||
|
||||
/// An implementation of `CurrencyToVote` tailored for chain's that have a balance type of u128.
|
||||
///
|
||||
/// The factor is the `(total_issuance / u64::max()).max(1)`, represented as u64. Let's look at the
|
||||
/// important cases:
|
||||
///
|
||||
/// If the chain's total issuance is less than u64::max(), this will always be 1, which means that
|
||||
/// the factor will not have any effect. In this case, any account's balance is also less. Thus,
|
||||
/// both of the conversions are basically an `as`; Any balance can fit in u64.
|
||||
///
|
||||
/// If the chain's total issuance is more than 2*u64::max(), then a factor might be multiplied and
|
||||
/// divided upon conversion.
|
||||
pub struct U128CurrencyToVote;
|
||||
|
||||
impl U128CurrencyToVote {
|
||||
fn factor(issuance: u128) -> u128 {
|
||||
(issuance / u64::max_value() as u128).max(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl CurrencyToVote<u128> for U128CurrencyToVote {
|
||||
fn to_vote(value: u128, issuance: u128) -> u64 {
|
||||
(value / Self::factor(issuance)).saturated_into()
|
||||
}
|
||||
|
||||
fn to_currency(value: u128, issuance: u128) -> u128 {
|
||||
value.saturating_mul(Self::factor(issuance))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A naive implementation of `CurrencyConvert` that simply saturates all conversions.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This is designed to be used mostly for testing. Use with care, and think about the consequences.
|
||||
pub struct SaturatingCurrencyToVote;
|
||||
|
||||
impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B> for SaturatingCurrencyToVote {
|
||||
fn to_vote(value: B, _: B) -> u64 {
|
||||
value.unique_saturated_into()
|
||||
}
|
||||
|
||||
fn to_currency(value: u128, _: B) -> B {
|
||||
B::unique_saturated_from(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -27,7 +27,7 @@ use sp_std::prelude::*;
|
||||
///
|
||||
/// Note that this will NOT attempt at normalizing the result.
|
||||
pub fn assignment_ratio_to_staked<A: IdentifierT, P: PerThing, FS>(
|
||||
ratio: Vec<Assignment<A, P>>,
|
||||
ratios: Vec<Assignment<A, P>>,
|
||||
stake_of: FS,
|
||||
) -> Vec<StakedAssignment<A>>
|
||||
where
|
||||
@@ -35,7 +35,7 @@ where
|
||||
P: sp_std::ops::Mul<ExtendedBalance, Output = ExtendedBalance>,
|
||||
ExtendedBalance: From<InnerOf<P>>,
|
||||
{
|
||||
ratio
|
||||
ratios
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
let stake = stake_of(&a.who);
|
||||
|
||||
Reference in New Issue
Block a user