mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 20:17:57 +00:00
Moving NposSolution to frame (#11031)
* Move `sp-npos-elections-solution-type` to `frame-election-provider-support` First stab at it, will need to amend some more stuff * Fixing tests * Fixing tests * Fixing cargo.toml for std configuration * fmt * Committing suggested changes renaming, and re exporting macro. * Removing unneeded imports * Move `NposSolution` to frame * Removing `npos_election` dependencies Implementing _fpes better * some feedback for moving NPoSSolution to frame * fmt * more formatting * Fixed some imports and fmt * Fixing docs Co-authored-by: kianenigma <kian@parity.io>
This commit is contained in:
Generated
+2
-2
@@ -2164,13 +2164,13 @@ dependencies = [
|
||||
name = "frame-election-provider-solution-type"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"frame-election-provider-support",
|
||||
"parity-scale-codec",
|
||||
"proc-macro-crate 1.1.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scale-info",
|
||||
"sp-arithmetic",
|
||||
"sp-npos-elections",
|
||||
"syn",
|
||||
"trybuild",
|
||||
]
|
||||
@@ -2198,6 +2198,7 @@ version = "2.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"clap 3.1.6",
|
||||
"frame-election-provider-solution-type",
|
||||
"frame-election-provider-support",
|
||||
"honggfuzz",
|
||||
"parity-scale-codec",
|
||||
"rand 0.8.4",
|
||||
@@ -5065,7 +5066,6 @@ dependencies = [
|
||||
"sp-core",
|
||||
"sp-inherents",
|
||||
"sp-io",
|
||||
"sp-npos-elections",
|
||||
"sp-offchain",
|
||||
"sp-runtime",
|
||||
"sp-sandbox",
|
||||
|
||||
@@ -38,7 +38,6 @@ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../..
|
||||
sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" }
|
||||
sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/transaction-pool" }
|
||||
sp-version = { version = "5.0.0", default-features = false, path = "../../../primitives/version" }
|
||||
sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" }
|
||||
sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" }
|
||||
sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" }
|
||||
|
||||
@@ -178,7 +177,6 @@ std = [
|
||||
"pallet-vesting/std",
|
||||
"log/std",
|
||||
"frame-try-runtime/std",
|
||||
"sp-npos-elections/std",
|
||||
"sp-io/std",
|
||||
"pallet-child-bounties/std",
|
||||
]
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_election_provider_support::onchain;
|
||||
use frame_election_provider_support::{onchain, ExtendedBalance, VoteWeight};
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types,
|
||||
construct_runtime,
|
||||
pallet_prelude::Get,
|
||||
parameter_types,
|
||||
traits::{
|
||||
AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf,
|
||||
EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem,
|
||||
@@ -598,7 +600,7 @@ frame_election_provider_support::generate_solution_type!(
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub MaxNominations: u32 = <NposSolution16 as sp_npos_elections::NposSolution>::LIMIT as u32;
|
||||
pub MaxNominations: u32 = <NposSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
|
||||
}
|
||||
|
||||
/// The numbers configured here could always be more than the the maximum limits of staking pallet
|
||||
@@ -621,10 +623,8 @@ pub const MINER_MAX_ITERATIONS: u32 = 10;
|
||||
|
||||
/// A source of random balance for NposSolver, which is meant to be run by the OCW election miner.
|
||||
pub struct OffchainRandomBalancing;
|
||||
impl frame_support::pallet_prelude::Get<Option<(usize, sp_npos_elections::ExtendedBalance)>>
|
||||
for OffchainRandomBalancing
|
||||
{
|
||||
fn get() -> Option<(usize, sp_npos_elections::ExtendedBalance)> {
|
||||
impl Get<Option<(usize, ExtendedBalance)>> for OffchainRandomBalancing {
|
||||
fn get() -> Option<(usize, ExtendedBalance)> {
|
||||
use sp_runtime::traits::TrailingZeroInput;
|
||||
let iters = match MINER_MAX_ITERATIONS {
|
||||
0 => 0,
|
||||
@@ -693,7 +693,7 @@ impl pallet_bags_list::Config for Runtime {
|
||||
type ScoreProvider = Staking;
|
||||
type WeightInfo = pallet_bags_list::weights::SubstrateWeight<Runtime>;
|
||||
type BagThresholds = BagThresholds;
|
||||
type Score = sp_npos_elections::VoteWeight;
|
||||
type Score = VoteWeight;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
|
||||
@@ -28,7 +28,6 @@ use frame_support::{
|
||||
use frame_system::RawOrigin;
|
||||
use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng};
|
||||
use sp_arithmetic::{per_things::Percent, traits::One};
|
||||
use sp_npos_elections::IndexAssignment;
|
||||
use sp_runtime::InnerOf;
|
||||
|
||||
const SEED: u32 = 999;
|
||||
@@ -461,6 +460,7 @@ frame_benchmarking::benchmarks! {
|
||||
T::BenchmarkingConfig::DESIRED_TARGETS[1];
|
||||
// Subtract this percentage from the actual encoded size
|
||||
let f in 0 .. 95;
|
||||
use frame_election_provider_support::IndexAssignment;
|
||||
|
||||
// Compute a random solution, then work backwards to get the lists of voters, targets, and
|
||||
// assignments
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_election_provider_support::{
|
||||
ElectionDataProvider, ElectionProvider, InstantElectionProvider,
|
||||
ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution,
|
||||
};
|
||||
use frame_support::{
|
||||
dispatch::DispatchResultWithPostInfo,
|
||||
@@ -246,8 +246,7 @@ use sp_arithmetic::{
|
||||
UpperOf,
|
||||
};
|
||||
use sp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, NposSolution, Supports,
|
||||
VoteWeight,
|
||||
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight,
|
||||
};
|
||||
use sp_runtime::{
|
||||
traits::Bounded,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use super::*;
|
||||
use crate as multi_phase;
|
||||
use frame_election_provider_support::{
|
||||
data_provider, onchain, ElectionDataProvider, SequentialPhragmen,
|
||||
data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen,
|
||||
};
|
||||
pub use frame_support::{assert_noop, assert_ok};
|
||||
use frame_support::{
|
||||
@@ -38,7 +38,7 @@ use sp_core::{
|
||||
};
|
||||
use sp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult,
|
||||
EvaluateSupport, ExtendedBalance, NposSolution,
|
||||
EvaluateSupport, ExtendedBalance,
|
||||
};
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
|
||||
@@ -23,12 +23,13 @@ use crate::{
|
||||
SolutionOrSnapshotSize, Weight, WeightInfo,
|
||||
};
|
||||
use codec::{Decode, Encode, HasCompact};
|
||||
use frame_election_provider_support::NposSolution;
|
||||
use frame_support::{
|
||||
storage::bounded_btree_map::BoundedBTreeMap,
|
||||
traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency},
|
||||
};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_npos_elections::{ElectionScore, NposSolution};
|
||||
use sp_npos_elections::ElectionScore;
|
||||
use sp_runtime::{
|
||||
traits::{Saturating, Zero},
|
||||
RuntimeDebug,
|
||||
|
||||
@@ -23,12 +23,11 @@ use crate::{
|
||||
WeightInfo,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_election_provider_support::{NposSolver, PerThing128};
|
||||
use frame_election_provider_support::{NposSolution, NposSolver, PerThing128};
|
||||
use frame_support::{dispatch::DispatchResult, ensure, traits::Get};
|
||||
use frame_system::offchain::SubmitTransaction;
|
||||
use sp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult,
|
||||
NposSolution,
|
||||
};
|
||||
use sp_runtime::{
|
||||
offchain::storage::{MutateStorageError, StorageValueRef},
|
||||
@@ -52,9 +51,9 @@ pub type VoterOf<T> = frame_election_provider_support::VoterOf<<T as Config>::Da
|
||||
pub type Assignment<T> =
|
||||
sp_npos_elections::Assignment<<T as frame_system::Config>::AccountId, SolutionAccuracyOf<T>>;
|
||||
|
||||
/// The [`IndexAssignment`][sp_npos_elections::IndexAssignment] type specialized for a particular
|
||||
/// runtime `T`.
|
||||
pub type IndexAssignmentOf<T> = sp_npos_elections::IndexAssignmentOf<SolutionOf<T>>;
|
||||
/// The [`IndexAssignment`][frame_election_provider_support::IndexAssignment] type specialized for a
|
||||
/// particular runtime `T`.
|
||||
pub type IndexAssignmentOf<T> = frame_election_provider_support::IndexAssignmentOf<SolutionOf<T>>;
|
||||
|
||||
/// Error type of the pallet's [`crate::Config::Solver`].
|
||||
pub type SolverErrorOf<T> = <<T as Config>::Solver as NposSolver>::Error;
|
||||
@@ -742,10 +741,11 @@ mod tests {
|
||||
};
|
||||
use codec::Decode;
|
||||
use frame_benchmarking::Zero;
|
||||
use frame_election_provider_support::IndexAssignment;
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker,
|
||||
};
|
||||
use sp_npos_elections::{ElectionScore, IndexAssignment};
|
||||
use sp_npos_elections::ElectionScore;
|
||||
use sp_runtime::{
|
||||
offchain::storage_lock::{BlockAndTime, StorageLock},
|
||||
traits::ValidateUnsigned,
|
||||
|
||||
@@ -25,5 +25,5 @@ parity-scale-codec = "3.0.0"
|
||||
scale-info = "2.0.1"
|
||||
sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" }
|
||||
# used by generate_solution_type:
|
||||
sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" }
|
||||
frame-election-provider-support = { version = "4.0.0-dev", path = ".." }
|
||||
trybuild = "1.0.53"
|
||||
|
||||
@@ -20,6 +20,7 @@ rand = { version = "0.8", features = ["std", "small_rng"] }
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
|
||||
frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." }
|
||||
frame-election-provider-support = { version = "4.0.0-dev", path = "../.." }
|
||||
sp-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" }
|
||||
sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" }
|
||||
# used by generate_solution_type:
|
||||
|
||||
@@ -51,14 +51,14 @@ fn decode_impl(
|
||||
quote! {
|
||||
let #name =
|
||||
<
|
||||
_npos::sp_std::prelude::Vec<(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)>
|
||||
_feps::sp_std::prelude::Vec<(_feps::codec::Compact<#voter_type>, _feps::codec::Compact<#target_type>)>
|
||||
as
|
||||
_npos::codec::Decode
|
||||
_feps::codec::Decode
|
||||
>::decode(value)?;
|
||||
let #name = #name
|
||||
.into_iter()
|
||||
.map(|(v, t)| (v.0, t.0))
|
||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
||||
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,12 +73,12 @@ fn decode_impl(
|
||||
quote! {
|
||||
let #name =
|
||||
<
|
||||
_npos::sp_std::prelude::Vec<(
|
||||
_npos::codec::Compact<#voter_type>,
|
||||
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
|
||||
_npos::codec::Compact<#target_type>,
|
||||
_feps::sp_std::prelude::Vec<(
|
||||
_feps::codec::Compact<#voter_type>,
|
||||
[(_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>); #c-1],
|
||||
_feps::codec::Compact<#target_type>,
|
||||
)>
|
||||
as _npos::codec::Decode
|
||||
as _feps::codec::Decode
|
||||
>::decode(value)?;
|
||||
let #name = #name
|
||||
.into_iter()
|
||||
@@ -87,7 +87,7 @@ fn decode_impl(
|
||||
[ #inner_impl ],
|
||||
t_last.0,
|
||||
))
|
||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
||||
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream2>();
|
||||
@@ -100,8 +100,8 @@ fn decode_impl(
|
||||
.collect::<TokenStream2>();
|
||||
|
||||
quote!(
|
||||
impl _npos::codec::Decode for #ident {
|
||||
fn decode<I: _npos::codec::Input>(value: &mut I) -> Result<Self, _npos::codec::Error> {
|
||||
impl _feps::codec::Decode for #ident {
|
||||
fn decode<I: _feps::codec::Input>(value: &mut I) -> Result<Self, _feps::codec::Error> {
|
||||
#decode_impl_single
|
||||
#decode_impl_rest
|
||||
|
||||
@@ -123,10 +123,10 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
|
||||
let #name = self.#name
|
||||
.iter()
|
||||
.map(|(v, t)| (
|
||||
_npos::codec::Compact(v.clone()),
|
||||
_npos::codec::Compact(t.clone()),
|
||||
_feps::codec::Compact(v.clone()),
|
||||
_feps::codec::Compact(t.clone()),
|
||||
))
|
||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
||||
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||
#name.encode_to(&mut r);
|
||||
}
|
||||
};
|
||||
@@ -139,8 +139,8 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
|
||||
let inners_solution_array = (0..c - 1)
|
||||
.map(|i| {
|
||||
quote! {(
|
||||
_npos::codec::Compact(inner[#i].0.clone()),
|
||||
_npos::codec::Compact(inner[#i].1.clone()),
|
||||
_feps::codec::Compact(inner[#i].0.clone()),
|
||||
_feps::codec::Compact(inner[#i].1.clone()),
|
||||
),}
|
||||
})
|
||||
.collect::<TokenStream2>();
|
||||
@@ -149,19 +149,19 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
|
||||
let #name = self.#name
|
||||
.iter()
|
||||
.map(|(v, inner, t_last)| (
|
||||
_npos::codec::Compact(v.clone()),
|
||||
_feps::codec::Compact(v.clone()),
|
||||
[ #inners_solution_array ],
|
||||
_npos::codec::Compact(t_last.clone()),
|
||||
_feps::codec::Compact(t_last.clone()),
|
||||
))
|
||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
||||
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||
#name.encode_to(&mut r);
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream2>();
|
||||
|
||||
quote!(
|
||||
impl _npos::codec::Encode for #ident {
|
||||
fn encode(&self) -> _npos::sp_std::prelude::Vec<u8> {
|
||||
impl _feps::codec::Encode for #ident {
|
||||
fn encode(&self) -> _feps::sp_std::prelude::Vec<u8> {
|
||||
let mut r = vec![];
|
||||
#encode_impl_single
|
||||
#encode_impl_rest
|
||||
@@ -182,8 +182,8 @@ fn scale_info_impl(
|
||||
let name = format!("{}", vote_field(1));
|
||||
quote! {
|
||||
.field(|f|
|
||||
f.ty::<_npos::sp_std::prelude::Vec<
|
||||
(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)
|
||||
f.ty::<_feps::sp_std::prelude::Vec<
|
||||
(_feps::codec::Compact<#voter_type>, _feps::codec::Compact<#target_type>)
|
||||
>>()
|
||||
.name(#name)
|
||||
)
|
||||
@@ -194,10 +194,10 @@ fn scale_info_impl(
|
||||
let name = format!("{}", vote_field(2));
|
||||
quote! {
|
||||
.field(|f|
|
||||
f.ty::<_npos::sp_std::prelude::Vec<(
|
||||
_npos::codec::Compact<#voter_type>,
|
||||
(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>),
|
||||
_npos::codec::Compact<#target_type>
|
||||
f.ty::<_feps::sp_std::prelude::Vec<(
|
||||
_feps::codec::Compact<#voter_type>,
|
||||
(_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>),
|
||||
_feps::codec::Compact<#target_type>
|
||||
)>>()
|
||||
.name(#name)
|
||||
)
|
||||
@@ -209,13 +209,13 @@ fn scale_info_impl(
|
||||
let name = format!("{}", vote_field(c));
|
||||
quote! {
|
||||
.field(|f|
|
||||
f.ty::<_npos::sp_std::prelude::Vec<(
|
||||
_npos::codec::Compact<#voter_type>,
|
||||
f.ty::<_feps::sp_std::prelude::Vec<(
|
||||
_feps::codec::Compact<#voter_type>,
|
||||
[
|
||||
(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>);
|
||||
(_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>);
|
||||
#c - 1
|
||||
],
|
||||
_npos::codec::Compact<#target_type>
|
||||
_feps::codec::Compact<#target_type>
|
||||
)>>()
|
||||
.name(#name)
|
||||
)
|
||||
@@ -224,14 +224,14 @@ fn scale_info_impl(
|
||||
.collect::<TokenStream2>();
|
||||
|
||||
quote!(
|
||||
impl _npos::scale_info::TypeInfo for #ident {
|
||||
impl _feps::scale_info::TypeInfo for #ident {
|
||||
type Identity = Self;
|
||||
|
||||
fn type_info() -> _npos::scale_info::Type<_npos::scale_info::form::MetaForm> {
|
||||
_npos::scale_info::Type::builder()
|
||||
.path(_npos::scale_info::Path::new(stringify!(#ident), module_path!()))
|
||||
fn type_info() -> _feps::scale_info::Type<_feps::scale_info::form::MetaForm> {
|
||||
_feps::scale_info::Type::builder()
|
||||
.path(_feps::scale_info::Path::new(stringify!(#ident), module_path!()))
|
||||
.composite(
|
||||
_npos::scale_info::build::Fields::named()
|
||||
_feps::scale_info::build::Fields::named()
|
||||
#scale_info_impl_single
|
||||
#scale_info_impl_double
|
||||
#scale_info_impl_rest
|
||||
|
||||
@@ -88,7 +88,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error {
|
||||
/// ```
|
||||
///
|
||||
/// The given struct provides function to convert from/to `Assignment` as part of
|
||||
/// `sp_npos_elections::Solution` trait:
|
||||
/// `frame_election_provider_support::NposSolution` trait:
|
||||
///
|
||||
/// - `fn from_assignment<..>(..)`
|
||||
/// - `fn into_assignment<..>(..)`
|
||||
@@ -101,7 +101,7 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error {
|
||||
///
|
||||
/// ```
|
||||
/// # use frame_election_provider_solution_type::generate_solution_type;
|
||||
/// # use sp_npos_elections::NposSolution;
|
||||
/// # use frame_election_provider_support::NposSolution;
|
||||
/// # use sp_arithmetic::per_things::Perbill;
|
||||
/// generate_solution_type!(
|
||||
/// #[compact]
|
||||
@@ -226,11 +226,11 @@ where
|
||||
}
|
||||
|
||||
fn imports() -> Result<TokenStream2> {
|
||||
match crate_name("sp-npos-elections") {
|
||||
Ok(FoundCrate::Itself) => Ok(quote! { use crate as _npos; }),
|
||||
Ok(FoundCrate::Name(sp_npos_elections)) => {
|
||||
let ident = syn::Ident::new(&sp_npos_elections, Span::call_site());
|
||||
Ok(quote!( extern crate #ident as _npos; ))
|
||||
match crate_name("frame-election-provider-support") {
|
||||
Ok(FoundCrate::Itself) => Ok(quote! { use crate as _feps; }),
|
||||
Ok(FoundCrate::Name(frame_election_provider_support)) => {
|
||||
let ident = syn::Ident::new(&frame_election_provider_support, Span::call_site());
|
||||
Ok(quote!( extern crate #ident as _feps; ))
|
||||
},
|
||||
Err(e) => Err(syn::Error::new(Span::call_site(), e)),
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
let name = vote_field(1);
|
||||
// NOTE: we use the visibility of the struct for the fields as well.. could be made better.
|
||||
quote!(
|
||||
#vis #name: _npos::sp_std::prelude::Vec<(#voter_type, #target_type)>,
|
||||
#vis #name: _feps::sp_std::prelude::Vec<(#voter_type, #target_type)>,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
let field_name = vote_field(c);
|
||||
let array_len = c - 1;
|
||||
quote!(
|
||||
#vis #field_name: _npos::sp_std::prelude::Vec<(
|
||||
#vis #field_name: _feps::sp_std::prelude::Vec<(
|
||||
#voter_type,
|
||||
[(#target_type, #weight_type); #array_len],
|
||||
#target_type
|
||||
@@ -83,9 +83,9 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
Eq,
|
||||
Clone,
|
||||
Debug,
|
||||
_npos::codec::Encode,
|
||||
_npos::codec::Decode,
|
||||
_npos::scale_info::TypeInfo,
|
||||
_feps::codec::Encode,
|
||||
_feps::codec::Decode,
|
||||
_feps::scale_info::TypeInfo,
|
||||
)])
|
||||
};
|
||||
|
||||
@@ -101,8 +101,8 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
#derives_and_maybe_compact_encoding
|
||||
#vis struct #ident { #single #rest }
|
||||
|
||||
use _npos::__OrInvalidIndex;
|
||||
impl _npos::NposSolution for #ident {
|
||||
use _feps::__OrInvalidIndex;
|
||||
impl _feps::NposSolution for #ident {
|
||||
const LIMIT: usize = #count;
|
||||
type VoterIndex = #voter_type;
|
||||
type TargetIndex = #target_type;
|
||||
@@ -114,34 +114,34 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
}
|
||||
|
||||
fn from_assignment<FV, FT, A>(
|
||||
assignments: &[_npos::Assignment<A, #weight_type>],
|
||||
assignments: &[_feps::Assignment<A, #weight_type>],
|
||||
voter_index: FV,
|
||||
target_index: FT,
|
||||
) -> Result<Self, _npos::Error>
|
||||
) -> Result<Self, _feps::Error>
|
||||
where
|
||||
A: _npos::IdentifierT,
|
||||
A: _feps::IdentifierT,
|
||||
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
||||
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>,
|
||||
{
|
||||
let mut #struct_name: #ident = Default::default();
|
||||
for _npos::Assignment { who, distribution } in assignments {
|
||||
for _feps::Assignment { who, distribution } in assignments {
|
||||
match distribution.len() {
|
||||
0 => continue,
|
||||
#from_impl
|
||||
_ => {
|
||||
return Err(_npos::Error::SolutionTargetOverflow);
|
||||
return Err(_feps::Error::SolutionTargetOverflow);
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(#struct_name)
|
||||
}
|
||||
|
||||
fn into_assignment<A: _npos::IdentifierT>(
|
||||
fn into_assignment<A: _feps::IdentifierT>(
|
||||
self,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<_npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>>, _npos::Error> {
|
||||
let mut #assignment_name: _npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>> = Default::default();
|
||||
) -> Result<_feps::sp_std::prelude::Vec<_feps::Assignment<A, #weight_type>>, _feps::Error> {
|
||||
let mut #assignment_name: _feps::sp_std::prelude::Vec<_feps::Assignment<A, #weight_type>> = Default::default();
|
||||
#into_impl
|
||||
Ok(#assignment_name)
|
||||
}
|
||||
@@ -158,10 +158,10 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
all_edges
|
||||
}
|
||||
|
||||
fn unique_targets(&self) -> _npos::sp_std::prelude::Vec<Self::TargetIndex> {
|
||||
fn unique_targets(&self) -> _feps::sp_std::prelude::Vec<Self::TargetIndex> {
|
||||
// NOTE: this implementation returns the targets sorted, but we don't use it yet per
|
||||
// se, nor is the API enforcing it.
|
||||
use _npos::sp_std::collections::btree_set::BTreeSet;
|
||||
use _feps::sp_std::collections::btree_set::BTreeSet;
|
||||
let mut all_targets: BTreeSet<Self::TargetIndex> = BTreeSet::new();
|
||||
let mut maybe_insert_target = |t: Self::TargetIndex| {
|
||||
all_targets.insert(t);
|
||||
@@ -173,22 +173,22 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
||||
}
|
||||
}
|
||||
|
||||
type __IndexAssignment = _npos::IndexAssignment<
|
||||
<#ident as _npos::NposSolution>::VoterIndex,
|
||||
<#ident as _npos::NposSolution>::TargetIndex,
|
||||
<#ident as _npos::NposSolution>::Accuracy,
|
||||
type __IndexAssignment = _feps::IndexAssignment<
|
||||
<#ident as _feps::NposSolution>::VoterIndex,
|
||||
<#ident as _feps::NposSolution>::TargetIndex,
|
||||
<#ident as _feps::NposSolution>::Accuracy,
|
||||
>;
|
||||
impl<'a> _npos::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident {
|
||||
type Error = _npos::Error;
|
||||
impl<'a> _feps::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident {
|
||||
type Error = _feps::Error;
|
||||
fn try_from(index_assignments: &'a [__IndexAssignment]) -> Result<Self, Self::Error> {
|
||||
let mut #struct_name = #ident::default();
|
||||
|
||||
for _npos::IndexAssignment { who, distribution } in index_assignments {
|
||||
for _feps::IndexAssignment { who, distribution } in index_assignments {
|
||||
match distribution.len() {
|
||||
0 => {}
|
||||
#from_index_impl
|
||||
_ => {
|
||||
return Err(_npos::Error::SolutionTargetOverflow);
|
||||
return Err(_feps::Error::SolutionTargetOverflow);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -310,7 +310,7 @@ pub(crate) fn into_impl(
|
||||
let name = vote_field(1);
|
||||
quote!(
|
||||
for (voter_index, target_index) in self.#name {
|
||||
#assignments.push(_npos::Assignment {
|
||||
#assignments.push(_feps::Assignment {
|
||||
who: voter_at(voter_index).or_invalid_index()?,
|
||||
distribution: vec![
|
||||
(target_at(target_index).or_invalid_index()?, #per_thing::one())
|
||||
@@ -329,25 +329,25 @@ pub(crate) fn into_impl(
|
||||
let mut inners_parsed = inners
|
||||
.iter()
|
||||
.map(|(ref t_idx, p)| {
|
||||
sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p);
|
||||
sum = _feps::sp_arithmetic::traits::Saturating::saturating_add(sum, *p);
|
||||
let target = target_at(*t_idx).or_invalid_index()?;
|
||||
Ok((target, *p))
|
||||
})
|
||||
.collect::<Result<_npos::sp_std::prelude::Vec<(A, #per_thing)>, _npos::Error>>()?;
|
||||
.collect::<Result<_feps::sp_std::prelude::Vec<(A, #per_thing)>, _feps::Error>>()?;
|
||||
|
||||
if sum >= #per_thing::one() {
|
||||
return Err(_npos::Error::SolutionWeightOverflow);
|
||||
return Err(_feps::Error::SolutionWeightOverflow);
|
||||
}
|
||||
|
||||
// defensive only. Since Percent doesn't have `Sub`.
|
||||
let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub(
|
||||
let p_last = _feps::sp_arithmetic::traits::Saturating::saturating_sub(
|
||||
#per_thing::one(),
|
||||
sum,
|
||||
);
|
||||
|
||||
inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last));
|
||||
|
||||
#assignments.push(_npos::Assignment {
|
||||
#assignments.push(_feps::Assignment {
|
||||
who: voter_at(voter_index).or_invalid_index()?,
|
||||
distribution: inners_parsed,
|
||||
});
|
||||
|
||||
@@ -167,17 +167,86 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod onchain;
|
||||
use frame_support::{traits::Get, BoundedVec};
|
||||
pub mod traits;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{traits::Get, BoundedVec, RuntimeDebug};
|
||||
use sp_runtime::traits::Bounded;
|
||||
use sp_std::{fmt::Debug, prelude::*};
|
||||
|
||||
/// Re-export some type as they are used in the interface.
|
||||
/// Re-export the solution generation macro.
|
||||
pub use frame_election_provider_solution_type::generate_solution_type;
|
||||
/// Re-export some type as they are used in the interface.
|
||||
pub use sp_arithmetic::PerThing;
|
||||
pub use sp_npos_elections::{
|
||||
Assignment, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Support, Supports,
|
||||
VoteWeight,
|
||||
Assignment, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, Support,
|
||||
Supports, VoteWeight,
|
||||
};
|
||||
pub use traits::NposSolution;
|
||||
|
||||
// re-export for the solution macro, with the dependencies of the macro.
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
#[doc(hidden)]
|
||||
pub use scale_info;
|
||||
#[doc(hidden)]
|
||||
pub use sp_arithmetic;
|
||||
#[doc(hidden)]
|
||||
pub use sp_std;
|
||||
// Simple Extension trait to easily convert `None` from index closures to `Err`.
|
||||
//
|
||||
// This is only generated and re-exported for the solution code to use.
|
||||
#[doc(hidden)]
|
||||
pub trait __OrInvalidIndex<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
impl<T> __OrInvalidIndex<T> for Option<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error> {
|
||||
self.ok_or(Error::SolutionInvalidIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`IndexAssignment`] type is an intermediate between the assignments list
|
||||
/// ([`&[Assignment<T>]`][Assignment]) and `SolutionOf<T>`.
|
||||
///
|
||||
/// The voter and target identifiers have already been replaced with appropriate indices,
|
||||
/// making it fast to repeatedly encode into a `SolutionOf<T>`. This property turns out
|
||||
/// to be important when trimming for solution length.
|
||||
#[derive(RuntimeDebug, Clone, Default)]
|
||||
#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))]
|
||||
pub struct IndexAssignment<VoterIndex, TargetIndex, P: PerThing> {
|
||||
/// Index of the voter among the voters list.
|
||||
pub who: VoterIndex,
|
||||
/// The distribution of the voter's stake among winning targets.
|
||||
///
|
||||
/// Targets are identified by their index in the canonical list.
|
||||
pub distribution: Vec<(TargetIndex, P)>,
|
||||
}
|
||||
|
||||
impl<VoterIndex, TargetIndex, P: PerThing> IndexAssignment<VoterIndex, TargetIndex, P> {
|
||||
pub fn new<AccountId: IdentifierT>(
|
||||
assignment: &Assignment<AccountId, P>,
|
||||
voter_index: impl Fn(&AccountId) -> Option<VoterIndex>,
|
||||
target_index: impl Fn(&AccountId) -> Option<TargetIndex>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
who: voter_index(&assignment.who).or_invalid_index()?,
|
||||
distribution: assignment
|
||||
.distribution
|
||||
.iter()
|
||||
.map(|(target, proportion)| Some((target_index(target)?, proportion.clone())))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.or_invalid_index()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias for [`IndexAssignment`] made from [`NposSolution`].
|
||||
pub type IndexAssignmentOf<C> = IndexAssignment<
|
||||
<C as NposSolution>::VoterIndex,
|
||||
<C as NposSolution>::TargetIndex,
|
||||
<C as NposSolution>::Accuracy,
|
||||
>;
|
||||
|
||||
/// Types that are used by the data provider trait.
|
||||
pub mod data_provider {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2022 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
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Traits for the election operations.
|
||||
|
||||
use crate::{Assignment, IdentifierT, IndexAssignmentOf, PerThing128, VoteWeight};
|
||||
use codec::Encode;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_arithmetic::traits::{Bounded, UniqueSaturatedInto};
|
||||
use sp_npos_elections::{ElectionScore, Error, EvaluateSupport};
|
||||
use sp_std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt::Debug,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// An opaque index-based, NPoS solution type.
|
||||
pub trait NposSolution
|
||||
where
|
||||
Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf<Self>], Error = Error>,
|
||||
{
|
||||
/// The maximum number of votes that are allowed.
|
||||
const LIMIT: usize;
|
||||
|
||||
/// The voter type. Needs to be an index (convert to usize).
|
||||
type VoterIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The target type. Needs to be an index (convert to usize).
|
||||
type TargetIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The weight/accuracy type of each vote.
|
||||
type Accuracy: PerThing128;
|
||||
|
||||
/// Get the length of all the voters that this type is encoding.
|
||||
///
|
||||
/// This is basically the same as the number of assignments, or number of active voters.
|
||||
fn voter_count(&self) -> usize;
|
||||
|
||||
/// Get the total count of edges.
|
||||
///
|
||||
/// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] *
|
||||
/// [`Self::LIMIT`]}.
|
||||
fn edge_count(&self) -> usize;
|
||||
|
||||
/// Get the number of unique targets in the whole struct.
|
||||
///
|
||||
/// Once presented with a list of winners, this set and the set of winners must be
|
||||
/// equal.
|
||||
fn unique_targets(&self) -> Vec<Self::TargetIndex>;
|
||||
|
||||
/// Get the average edge count.
|
||||
fn average_edge_count(&self) -> usize {
|
||||
self.edge_count().checked_div(self.voter_count()).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Compute the score of this solution type.
|
||||
fn score<A, FS>(
|
||||
self,
|
||||
stake_of: FS,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<ElectionScore, Error>
|
||||
where
|
||||
for<'r> FS: Fn(&'r A) -> VoteWeight,
|
||||
A: IdentifierT,
|
||||
{
|
||||
let ratio = self.into_assignment(voter_at, target_at)?;
|
||||
let staked =
|
||||
sp_npos_elections::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?;
|
||||
let supports = sp_npos_elections::to_supports(&staked);
|
||||
Ok(supports.evaluate())
|
||||
}
|
||||
|
||||
/// Remove a certain voter.
|
||||
///
|
||||
/// This will only search until the first instance of `to_remove`, and return true. If
|
||||
/// no instance is found (no-op), then it returns false.
|
||||
///
|
||||
/// In other words, if this return true, exactly **one** element must have been removed self.
|
||||
fn remove_voter(&mut self, to_remove: Self::VoterIndex) -> bool;
|
||||
|
||||
/// Build self from a list of assignments.
|
||||
fn from_assignment<FV, FT, A>(
|
||||
assignments: &[Assignment<A, Self::Accuracy>],
|
||||
voter_index: FV,
|
||||
target_index: FT,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
A: IdentifierT,
|
||||
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
||||
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>;
|
||||
|
||||
/// Convert self into a `Vec<Assignment<A, Self::Accuracy>>`
|
||||
fn into_assignment<A: IdentifierT>(
|
||||
self,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<Vec<Assignment<A, Self::Accuracy>>, Error>;
|
||||
}
|
||||
@@ -40,9 +40,9 @@ mod impls;
|
||||
pub use impls::*;
|
||||
|
||||
use crate::{
|
||||
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints,
|
||||
Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf,
|
||||
Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
|
||||
slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure,
|
||||
Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases,
|
||||
RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
|
||||
ValidatorPrefs,
|
||||
};
|
||||
|
||||
@@ -554,7 +554,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
for &(ref stash, ref controller, balance, ref status) in &self.stakers {
|
||||
log!(
|
||||
crate::log!(
|
||||
trace,
|
||||
"inserting genesis staker: {:?} => {:?} => {:?}",
|
||||
stash,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
//! Structs and helpers for distributing a voter's stake among various winners.
|
||||
|
||||
use crate::{Error, ExtendedBalance, IdentifierT, PerThing128, __OrInvalidIndex};
|
||||
use crate::{ExtendedBalance, IdentifierT, PerThing128};
|
||||
#[cfg(feature = "std")]
|
||||
use codec::{Decode, Encode};
|
||||
use sp_arithmetic::{
|
||||
@@ -166,44 +166,3 @@ impl<AccountId> StakedAssignment<AccountId> {
|
||||
self.distribution.iter().fold(Zero::zero(), |a, b| a.saturating_add(b.1))
|
||||
}
|
||||
}
|
||||
/// The [`IndexAssignment`] type is an intermediate between the assignments list
|
||||
/// ([`&[Assignment<T>]`][Assignment]) and `SolutionOf<T>`.
|
||||
///
|
||||
/// The voter and target identifiers have already been replaced with appropriate indices,
|
||||
/// making it fast to repeatedly encode into a `SolutionOf<T>`. This property turns out
|
||||
/// to be important when trimming for solution length.
|
||||
#[derive(RuntimeDebug, Clone, Default)]
|
||||
#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))]
|
||||
pub struct IndexAssignment<VoterIndex, TargetIndex, P: PerThing> {
|
||||
/// Index of the voter among the voters list.
|
||||
pub who: VoterIndex,
|
||||
/// The distribution of the voter's stake among winning targets.
|
||||
///
|
||||
/// Targets are identified by their index in the canonical list.
|
||||
pub distribution: Vec<(TargetIndex, P)>,
|
||||
}
|
||||
|
||||
impl<VoterIndex, TargetIndex, P: PerThing> IndexAssignment<VoterIndex, TargetIndex, P> {
|
||||
pub fn new<AccountId: IdentifierT>(
|
||||
assignment: &Assignment<AccountId, P>,
|
||||
voter_index: impl Fn(&AccountId) -> Option<VoterIndex>,
|
||||
target_index: impl Fn(&AccountId) -> Option<TargetIndex>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
who: voter_index(&assignment.who).or_invalid_index()?,
|
||||
distribution: assignment
|
||||
.distribution
|
||||
.iter()
|
||||
.map(|(target, proportion)| Some((target_index(target)?, proportion.clone())))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.or_invalid_index()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias for [`IndexAssignment`] made from [`crate::NposSolution`].
|
||||
pub type IndexAssignmentOf<C> = IndexAssignment<
|
||||
<C as crate::NposSolution>::VoterIndex,
|
||||
<C as crate::NposSolution>::TargetIndex,
|
||||
<C as crate::NposSolution>::Accuracy,
|
||||
>;
|
||||
|
||||
@@ -100,26 +100,16 @@ pub mod pjr;
|
||||
pub mod reduce;
|
||||
pub mod traits;
|
||||
|
||||
pub use assignments::{Assignment, IndexAssignment, IndexAssignmentOf, StakedAssignment};
|
||||
pub use assignments::{Assignment, StakedAssignment};
|
||||
pub use balancing::*;
|
||||
pub use helpers::*;
|
||||
pub use phragmen::*;
|
||||
pub use phragmms::*;
|
||||
pub use pjr::*;
|
||||
pub use reduce::reduce;
|
||||
pub use traits::{IdentifierT, NposSolution, PerThing128, __OrInvalidIndex};
|
||||
pub use traits::{IdentifierT, PerThing128};
|
||||
|
||||
// re-export for the solution macro, with the dependencies of the macro.
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
#[doc(hidden)]
|
||||
pub use scale_info;
|
||||
#[doc(hidden)]
|
||||
pub use sp_arithmetic;
|
||||
#[doc(hidden)]
|
||||
pub use sp_std;
|
||||
|
||||
/// The errors that might occur in the this crate and solution-type.
|
||||
/// The errors that might occur in this crate and `frame-election-provider-solution-type`.
|
||||
#[derive(Eq, PartialEq, RuntimeDebug)]
|
||||
pub enum Error {
|
||||
/// While going from solution indices to ratio, the weight of all the edges has gone above the
|
||||
|
||||
@@ -17,22 +17,9 @@
|
||||
|
||||
//! Traits for the npos-election operations.
|
||||
|
||||
use crate::{
|
||||
Assignment, ElectionScore, Error, EvaluateSupport, ExtendedBalance, IndexAssignmentOf,
|
||||
VoteWeight,
|
||||
};
|
||||
use codec::Encode;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_arithmetic::{
|
||||
traits::{Bounded, UniqueSaturatedInto},
|
||||
PerThing,
|
||||
};
|
||||
use sp_std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt::Debug,
|
||||
ops::Mul,
|
||||
prelude::*,
|
||||
};
|
||||
use crate::ExtendedBalance;
|
||||
use sp_arithmetic::PerThing;
|
||||
use sp_std::{fmt::Debug, ops::Mul, prelude::*};
|
||||
|
||||
/// an aggregator trait for a generic type of a voter/target identifier. This usually maps to
|
||||
/// substrate's account id.
|
||||
@@ -42,116 +29,3 @@ impl<T: Clone + Eq + Ord + Debug + codec::Codec> IdentifierT for T {}
|
||||
/// Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance).
|
||||
pub trait PerThing128: PerThing + Mul<ExtendedBalance, Output = ExtendedBalance> {}
|
||||
impl<T: PerThing + Mul<ExtendedBalance, Output = ExtendedBalance>> PerThing128 for T {}
|
||||
|
||||
/// Simple Extension trait to easily convert `None` from index closures to `Err`.
|
||||
///
|
||||
/// This is only generated and re-exported for the solution code to use.
|
||||
#[doc(hidden)]
|
||||
pub trait __OrInvalidIndex<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
impl<T> __OrInvalidIndex<T> for Option<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error> {
|
||||
self.ok_or(Error::SolutionInvalidIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/// An opaque index-based, NPoS solution type.
|
||||
pub trait NposSolution
|
||||
where
|
||||
Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf<Self>], Error = Error>,
|
||||
{
|
||||
/// The maximum number of votes that are allowed.
|
||||
const LIMIT: usize;
|
||||
|
||||
/// The voter type. Needs to be an index (convert to usize).
|
||||
type VoterIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The target type. Needs to be an index (convert to usize).
|
||||
type TargetIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The weight/accuracy type of each vote.
|
||||
type Accuracy: PerThing128;
|
||||
|
||||
/// Get the length of all the voters that this type is encoding.
|
||||
///
|
||||
/// This is basically the same as the number of assignments, or number of active voters.
|
||||
fn voter_count(&self) -> usize;
|
||||
|
||||
/// Get the total count of edges.
|
||||
///
|
||||
/// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] *
|
||||
/// [`Self::LIMIT`]}.
|
||||
fn edge_count(&self) -> usize;
|
||||
|
||||
/// Get the number of unique targets in the whole struct.
|
||||
///
|
||||
/// Once presented with a list of winners, this set and the set of winners must be
|
||||
/// equal.
|
||||
fn unique_targets(&self) -> Vec<Self::TargetIndex>;
|
||||
|
||||
/// Get the average edge count.
|
||||
fn average_edge_count(&self) -> usize {
|
||||
self.edge_count().checked_div(self.voter_count()).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Compute the score of this solution type.
|
||||
fn score<A, FS>(
|
||||
self,
|
||||
stake_of: FS,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<ElectionScore, Error>
|
||||
where
|
||||
for<'r> FS: Fn(&'r A) -> VoteWeight,
|
||||
A: IdentifierT,
|
||||
{
|
||||
let ratio = self.into_assignment(voter_at, target_at)?;
|
||||
let staked = crate::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?;
|
||||
let supports = crate::to_supports(&staked);
|
||||
Ok(supports.evaluate())
|
||||
}
|
||||
|
||||
/// Remove a certain voter.
|
||||
///
|
||||
/// This will only search until the first instance of `to_remove`, and return true. If
|
||||
/// no instance is found (no-op), then it returns false.
|
||||
///
|
||||
/// In other words, if this return true, exactly **one** element must have been removed self.
|
||||
fn remove_voter(&mut self, to_remove: Self::VoterIndex) -> bool;
|
||||
|
||||
/// Build self from a list of assignments.
|
||||
fn from_assignment<FV, FT, A>(
|
||||
assignments: &[Assignment<A, Self::Accuracy>],
|
||||
voter_index: FV,
|
||||
target_index: FT,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
A: IdentifierT,
|
||||
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
||||
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>;
|
||||
|
||||
/// Convert self into a `Vec<Assignment<A, Self::Accuracy>>`
|
||||
fn into_assignment<A: IdentifierT>(
|
||||
self,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<Vec<Assignment<A, Self::Accuracy>>, Error>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user