mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 22:41:06 +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"
|
name = "frame-election-provider-solution-type"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"frame-election-provider-support",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"proc-macro-crate 1.1.0",
|
"proc-macro-crate 1.1.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
"sp-arithmetic",
|
"sp-arithmetic",
|
||||||
"sp-npos-elections",
|
|
||||||
"syn",
|
"syn",
|
||||||
"trybuild",
|
"trybuild",
|
||||||
]
|
]
|
||||||
@@ -2198,6 +2198,7 @@ version = "2.0.0-alpha.5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 3.1.6",
|
"clap 3.1.6",
|
||||||
"frame-election-provider-solution-type",
|
"frame-election-provider-solution-type",
|
||||||
|
"frame-election-provider-support",
|
||||||
"honggfuzz",
|
"honggfuzz",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand 0.8.4",
|
"rand 0.8.4",
|
||||||
@@ -5065,7 +5066,6 @@ dependencies = [
|
|||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-inherents",
|
"sp-inherents",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-npos-elections",
|
|
||||||
"sp-offchain",
|
"sp-offchain",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-sandbox",
|
"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-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-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-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-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" }
|
||||||
sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" }
|
sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" }
|
||||||
|
|
||||||
@@ -178,7 +177,6 @@ std = [
|
|||||||
"pallet-vesting/std",
|
"pallet-vesting/std",
|
||||||
"log/std",
|
"log/std",
|
||||||
"frame-try-runtime/std",
|
"frame-try-runtime/std",
|
||||||
"sp-npos-elections/std",
|
|
||||||
"sp-io/std",
|
"sp-io/std",
|
||||||
"pallet-child-bounties/std",
|
"pallet-child-bounties/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,9 +23,11 @@
|
|||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
use codec::{Decode, Encode, MaxEncodedLen};
|
use codec::{Decode, Encode, MaxEncodedLen};
|
||||||
use frame_election_provider_support::onchain;
|
use frame_election_provider_support::{onchain, ExtendedBalance, VoteWeight};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
construct_runtime, parameter_types,
|
construct_runtime,
|
||||||
|
pallet_prelude::Get,
|
||||||
|
parameter_types,
|
||||||
traits::{
|
traits::{
|
||||||
AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf,
|
AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EnsureOneOf,
|
||||||
EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem,
|
EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem,
|
||||||
@@ -598,7 +600,7 @@ frame_election_provider_support::generate_solution_type!(
|
|||||||
);
|
);
|
||||||
|
|
||||||
parameter_types! {
|
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
|
/// 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.
|
/// A source of random balance for NposSolver, which is meant to be run by the OCW election miner.
|
||||||
pub struct OffchainRandomBalancing;
|
pub struct OffchainRandomBalancing;
|
||||||
impl frame_support::pallet_prelude::Get<Option<(usize, sp_npos_elections::ExtendedBalance)>>
|
impl Get<Option<(usize, ExtendedBalance)>> for OffchainRandomBalancing {
|
||||||
for OffchainRandomBalancing
|
fn get() -> Option<(usize, ExtendedBalance)> {
|
||||||
{
|
|
||||||
fn get() -> Option<(usize, sp_npos_elections::ExtendedBalance)> {
|
|
||||||
use sp_runtime::traits::TrailingZeroInput;
|
use sp_runtime::traits::TrailingZeroInput;
|
||||||
let iters = match MINER_MAX_ITERATIONS {
|
let iters = match MINER_MAX_ITERATIONS {
|
||||||
0 => 0,
|
0 => 0,
|
||||||
@@ -693,7 +693,7 @@ impl pallet_bags_list::Config for Runtime {
|
|||||||
type ScoreProvider = Staking;
|
type ScoreProvider = Staking;
|
||||||
type WeightInfo = pallet_bags_list::weights::SubstrateWeight<Runtime>;
|
type WeightInfo = pallet_bags_list::weights::SubstrateWeight<Runtime>;
|
||||||
type BagThresholds = BagThresholds;
|
type BagThresholds = BagThresholds;
|
||||||
type Score = sp_npos_elections::VoteWeight;
|
type Score = VoteWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ use frame_support::{
|
|||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng};
|
use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng};
|
||||||
use sp_arithmetic::{per_things::Percent, traits::One};
|
use sp_arithmetic::{per_things::Percent, traits::One};
|
||||||
use sp_npos_elections::IndexAssignment;
|
|
||||||
use sp_runtime::InnerOf;
|
use sp_runtime::InnerOf;
|
||||||
|
|
||||||
const SEED: u32 = 999;
|
const SEED: u32 = 999;
|
||||||
@@ -461,6 +460,7 @@ frame_benchmarking::benchmarks! {
|
|||||||
T::BenchmarkingConfig::DESIRED_TARGETS[1];
|
T::BenchmarkingConfig::DESIRED_TARGETS[1];
|
||||||
// Subtract this percentage from the actual encoded size
|
// Subtract this percentage from the actual encoded size
|
||||||
let f in 0 .. 95;
|
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
|
// Compute a random solution, then work backwards to get the lists of voters, targets, and
|
||||||
// assignments
|
// assignments
|
||||||
|
|||||||
@@ -231,7 +231,7 @@
|
|||||||
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_election_provider_support::{
|
use frame_election_provider_support::{
|
||||||
ElectionDataProvider, ElectionProvider, InstantElectionProvider,
|
ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution,
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
dispatch::DispatchResultWithPostInfo,
|
dispatch::DispatchResultWithPostInfo,
|
||||||
@@ -246,8 +246,7 @@ use sp_arithmetic::{
|
|||||||
UpperOf,
|
UpperOf,
|
||||||
};
|
};
|
||||||
use sp_npos_elections::{
|
use sp_npos_elections::{
|
||||||
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, NposSolution, Supports,
|
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight,
|
||||||
VoteWeight,
|
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::Bounded,
|
traits::Bounded,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate as multi_phase;
|
use crate as multi_phase;
|
||||||
use frame_election_provider_support::{
|
use frame_election_provider_support::{
|
||||||
data_provider, onchain, ElectionDataProvider, SequentialPhragmen,
|
data_provider, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen,
|
||||||
};
|
};
|
||||||
pub use frame_support::{assert_noop, assert_ok};
|
pub use frame_support::{assert_noop, assert_ok};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
@@ -38,7 +38,7 @@ use sp_core::{
|
|||||||
};
|
};
|
||||||
use sp_npos_elections::{
|
use sp_npos_elections::{
|
||||||
assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult,
|
assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult,
|
||||||
EvaluateSupport, ExtendedBalance, NposSolution,
|
EvaluateSupport, ExtendedBalance,
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
testing::Header,
|
testing::Header,
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ use crate::{
|
|||||||
SolutionOrSnapshotSize, Weight, WeightInfo,
|
SolutionOrSnapshotSize, Weight, WeightInfo,
|
||||||
};
|
};
|
||||||
use codec::{Decode, Encode, HasCompact};
|
use codec::{Decode, Encode, HasCompact};
|
||||||
|
use frame_election_provider_support::NposSolution;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
storage::bounded_btree_map::BoundedBTreeMap,
|
storage::bounded_btree_map::BoundedBTreeMap,
|
||||||
traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency},
|
traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency},
|
||||||
};
|
};
|
||||||
use sp_arithmetic::traits::SaturatedConversion;
|
use sp_arithmetic::traits::SaturatedConversion;
|
||||||
use sp_npos_elections::{ElectionScore, NposSolution};
|
use sp_npos_elections::ElectionScore;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{Saturating, Zero},
|
traits::{Saturating, Zero},
|
||||||
RuntimeDebug,
|
RuntimeDebug,
|
||||||
|
|||||||
@@ -23,12 +23,11 @@ use crate::{
|
|||||||
WeightInfo,
|
WeightInfo,
|
||||||
};
|
};
|
||||||
use codec::Encode;
|
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_support::{dispatch::DispatchResult, ensure, traits::Get};
|
||||||
use frame_system::offchain::SubmitTransaction;
|
use frame_system::offchain::SubmitTransaction;
|
||||||
use sp_npos_elections::{
|
use sp_npos_elections::{
|
||||||
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult,
|
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult,
|
||||||
NposSolution,
|
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
offchain::storage::{MutateStorageError, StorageValueRef},
|
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> =
|
pub type Assignment<T> =
|
||||||
sp_npos_elections::Assignment<<T as frame_system::Config>::AccountId, SolutionAccuracyOf<T>>;
|
sp_npos_elections::Assignment<<T as frame_system::Config>::AccountId, SolutionAccuracyOf<T>>;
|
||||||
|
|
||||||
/// The [`IndexAssignment`][sp_npos_elections::IndexAssignment] type specialized for a particular
|
/// The [`IndexAssignment`][frame_election_provider_support::IndexAssignment] type specialized for a
|
||||||
/// runtime `T`.
|
/// particular runtime `T`.
|
||||||
pub type IndexAssignmentOf<T> = sp_npos_elections::IndexAssignmentOf<SolutionOf<T>>;
|
pub type IndexAssignmentOf<T> = frame_election_provider_support::IndexAssignmentOf<SolutionOf<T>>;
|
||||||
|
|
||||||
/// Error type of the pallet's [`crate::Config::Solver`].
|
/// Error type of the pallet's [`crate::Config::Solver`].
|
||||||
pub type SolverErrorOf<T> = <<T as Config>::Solver as NposSolver>::Error;
|
pub type SolverErrorOf<T> = <<T as Config>::Solver as NposSolver>::Error;
|
||||||
@@ -742,10 +741,11 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use frame_benchmarking::Zero;
|
use frame_benchmarking::Zero;
|
||||||
|
use frame_election_provider_support::IndexAssignment;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker,
|
assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker,
|
||||||
};
|
};
|
||||||
use sp_npos_elections::{ElectionScore, IndexAssignment};
|
use sp_npos_elections::ElectionScore;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
offchain::storage_lock::{BlockAndTime, StorageLock},
|
offchain::storage_lock::{BlockAndTime, StorageLock},
|
||||||
traits::ValidateUnsigned,
|
traits::ValidateUnsigned,
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ parity-scale-codec = "3.0.0"
|
|||||||
scale-info = "2.0.1"
|
scale-info = "2.0.1"
|
||||||
sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" }
|
sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" }
|
||||||
# used by generate_solution_type:
|
# 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"
|
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"] }
|
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"] }
|
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-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-arithmetic = { version = "5.0.0", path = "../../../../primitives/arithmetic" }
|
||||||
sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" }
|
sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" }
|
||||||
# used by generate_solution_type:
|
# used by generate_solution_type:
|
||||||
|
|||||||
@@ -51,14 +51,14 @@ fn decode_impl(
|
|||||||
quote! {
|
quote! {
|
||||||
let #name =
|
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
|
as
|
||||||
_npos::codec::Decode
|
_feps::codec::Decode
|
||||||
>::decode(value)?;
|
>::decode(value)?;
|
||||||
let #name = #name
|
let #name = #name
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(v, t)| (v.0, t.0))
|
.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! {
|
quote! {
|
||||||
let #name =
|
let #name =
|
||||||
<
|
<
|
||||||
_npos::sp_std::prelude::Vec<(
|
_feps::sp_std::prelude::Vec<(
|
||||||
_npos::codec::Compact<#voter_type>,
|
_feps::codec::Compact<#voter_type>,
|
||||||
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
|
[(_feps::codec::Compact<#target_type>, _feps::codec::Compact<#weight_type>); #c-1],
|
||||||
_npos::codec::Compact<#target_type>,
|
_feps::codec::Compact<#target_type>,
|
||||||
)>
|
)>
|
||||||
as _npos::codec::Decode
|
as _feps::codec::Decode
|
||||||
>::decode(value)?;
|
>::decode(value)?;
|
||||||
let #name = #name
|
let #name = #name
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -87,7 +87,7 @@ fn decode_impl(
|
|||||||
[ #inner_impl ],
|
[ #inner_impl ],
|
||||||
t_last.0,
|
t_last.0,
|
||||||
))
|
))
|
||||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<TokenStream2>();
|
.collect::<TokenStream2>();
|
||||||
@@ -100,8 +100,8 @@ fn decode_impl(
|
|||||||
.collect::<TokenStream2>();
|
.collect::<TokenStream2>();
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
impl _npos::codec::Decode for #ident {
|
impl _feps::codec::Decode for #ident {
|
||||||
fn decode<I: _npos::codec::Input>(value: &mut I) -> Result<Self, _npos::codec::Error> {
|
fn decode<I: _feps::codec::Input>(value: &mut I) -> Result<Self, _feps::codec::Error> {
|
||||||
#decode_impl_single
|
#decode_impl_single
|
||||||
#decode_impl_rest
|
#decode_impl_rest
|
||||||
|
|
||||||
@@ -123,10 +123,10 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
|
|||||||
let #name = self.#name
|
let #name = self.#name
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(v, t)| (
|
.map(|(v, t)| (
|
||||||
_npos::codec::Compact(v.clone()),
|
_feps::codec::Compact(v.clone()),
|
||||||
_npos::codec::Compact(t.clone()),
|
_feps::codec::Compact(t.clone()),
|
||||||
))
|
))
|
||||||
.collect::<_npos::sp_std::prelude::Vec<_>>();
|
.collect::<_feps::sp_std::prelude::Vec<_>>();
|
||||||
#name.encode_to(&mut r);
|
#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)
|
let inners_solution_array = (0..c - 1)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
quote! {(
|
quote! {(
|
||||||
_npos::codec::Compact(inner[#i].0.clone()),
|
_feps::codec::Compact(inner[#i].0.clone()),
|
||||||
_npos::codec::Compact(inner[#i].1.clone()),
|
_feps::codec::Compact(inner[#i].1.clone()),
|
||||||
),}
|
),}
|
||||||
})
|
})
|
||||||
.collect::<TokenStream2>();
|
.collect::<TokenStream2>();
|
||||||
@@ -149,19 +149,19 @@ fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
|
|||||||
let #name = self.#name
|
let #name = self.#name
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(v, inner, t_last)| (
|
.map(|(v, inner, t_last)| (
|
||||||
_npos::codec::Compact(v.clone()),
|
_feps::codec::Compact(v.clone()),
|
||||||
[ #inners_solution_array ],
|
[ #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);
|
#name.encode_to(&mut r);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<TokenStream2>();
|
.collect::<TokenStream2>();
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
impl _npos::codec::Encode for #ident {
|
impl _feps::codec::Encode for #ident {
|
||||||
fn encode(&self) -> _npos::sp_std::prelude::Vec<u8> {
|
fn encode(&self) -> _feps::sp_std::prelude::Vec<u8> {
|
||||||
let mut r = vec![];
|
let mut r = vec![];
|
||||||
#encode_impl_single
|
#encode_impl_single
|
||||||
#encode_impl_rest
|
#encode_impl_rest
|
||||||
@@ -182,8 +182,8 @@ fn scale_info_impl(
|
|||||||
let name = format!("{}", vote_field(1));
|
let name = format!("{}", vote_field(1));
|
||||||
quote! {
|
quote! {
|
||||||
.field(|f|
|
.field(|f|
|
||||||
f.ty::<_npos::sp_std::prelude::Vec<
|
f.ty::<_feps::sp_std::prelude::Vec<
|
||||||
(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)
|
(_feps::codec::Compact<#voter_type>, _feps::codec::Compact<#target_type>)
|
||||||
>>()
|
>>()
|
||||||
.name(#name)
|
.name(#name)
|
||||||
)
|
)
|
||||||
@@ -194,10 +194,10 @@ fn scale_info_impl(
|
|||||||
let name = format!("{}", vote_field(2));
|
let name = format!("{}", vote_field(2));
|
||||||
quote! {
|
quote! {
|
||||||
.field(|f|
|
.field(|f|
|
||||||
f.ty::<_npos::sp_std::prelude::Vec<(
|
f.ty::<_feps::sp_std::prelude::Vec<(
|
||||||
_npos::codec::Compact<#voter_type>,
|
_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>),
|
||||||
_npos::codec::Compact<#target_type>
|
_feps::codec::Compact<#target_type>
|
||||||
)>>()
|
)>>()
|
||||||
.name(#name)
|
.name(#name)
|
||||||
)
|
)
|
||||||
@@ -209,13 +209,13 @@ fn scale_info_impl(
|
|||||||
let name = format!("{}", vote_field(c));
|
let name = format!("{}", vote_field(c));
|
||||||
quote! {
|
quote! {
|
||||||
.field(|f|
|
.field(|f|
|
||||||
f.ty::<_npos::sp_std::prelude::Vec<(
|
f.ty::<_feps::sp_std::prelude::Vec<(
|
||||||
_npos::codec::Compact<#voter_type>,
|
_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
|
#c - 1
|
||||||
],
|
],
|
||||||
_npos::codec::Compact<#target_type>
|
_feps::codec::Compact<#target_type>
|
||||||
)>>()
|
)>>()
|
||||||
.name(#name)
|
.name(#name)
|
||||||
)
|
)
|
||||||
@@ -224,14 +224,14 @@ fn scale_info_impl(
|
|||||||
.collect::<TokenStream2>();
|
.collect::<TokenStream2>();
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
impl _npos::scale_info::TypeInfo for #ident {
|
impl _feps::scale_info::TypeInfo for #ident {
|
||||||
type Identity = Self;
|
type Identity = Self;
|
||||||
|
|
||||||
fn type_info() -> _npos::scale_info::Type<_npos::scale_info::form::MetaForm> {
|
fn type_info() -> _feps::scale_info::Type<_feps::scale_info::form::MetaForm> {
|
||||||
_npos::scale_info::Type::builder()
|
_feps::scale_info::Type::builder()
|
||||||
.path(_npos::scale_info::Path::new(stringify!(#ident), module_path!()))
|
.path(_feps::scale_info::Path::new(stringify!(#ident), module_path!()))
|
||||||
.composite(
|
.composite(
|
||||||
_npos::scale_info::build::Fields::named()
|
_feps::scale_info::build::Fields::named()
|
||||||
#scale_info_impl_single
|
#scale_info_impl_single
|
||||||
#scale_info_impl_double
|
#scale_info_impl_double
|
||||||
#scale_info_impl_rest
|
#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
|
/// 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 from_assignment<..>(..)`
|
||||||
/// - `fn into_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 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;
|
/// # use sp_arithmetic::per_things::Perbill;
|
||||||
/// generate_solution_type!(
|
/// generate_solution_type!(
|
||||||
/// #[compact]
|
/// #[compact]
|
||||||
@@ -226,11 +226,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn imports() -> Result<TokenStream2> {
|
fn imports() -> Result<TokenStream2> {
|
||||||
match crate_name("sp-npos-elections") {
|
match crate_name("frame-election-provider-support") {
|
||||||
Ok(FoundCrate::Itself) => Ok(quote! { use crate as _npos; }),
|
Ok(FoundCrate::Itself) => Ok(quote! { use crate as _feps; }),
|
||||||
Ok(FoundCrate::Name(sp_npos_elections)) => {
|
Ok(FoundCrate::Name(frame_election_provider_support)) => {
|
||||||
let ident = syn::Ident::new(&sp_npos_elections, Span::call_site());
|
let ident = syn::Ident::new(&frame_election_provider_support, Span::call_site());
|
||||||
Ok(quote!( extern crate #ident as _npos; ))
|
Ok(quote!( extern crate #ident as _feps; ))
|
||||||
},
|
},
|
||||||
Err(e) => Err(syn::Error::new(Span::call_site(), e)),
|
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);
|
let name = vote_field(1);
|
||||||
// NOTE: we use the visibility of the struct for the fields as well.. could be made better.
|
// NOTE: we use the visibility of the struct for the fields as well.. could be made better.
|
||||||
quote!(
|
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 field_name = vote_field(c);
|
||||||
let array_len = c - 1;
|
let array_len = c - 1;
|
||||||
quote!(
|
quote!(
|
||||||
#vis #field_name: _npos::sp_std::prelude::Vec<(
|
#vis #field_name: _feps::sp_std::prelude::Vec<(
|
||||||
#voter_type,
|
#voter_type,
|
||||||
[(#target_type, #weight_type); #array_len],
|
[(#target_type, #weight_type); #array_len],
|
||||||
#target_type
|
#target_type
|
||||||
@@ -83,9 +83,9 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
|||||||
Eq,
|
Eq,
|
||||||
Clone,
|
Clone,
|
||||||
Debug,
|
Debug,
|
||||||
_npos::codec::Encode,
|
_feps::codec::Encode,
|
||||||
_npos::codec::Decode,
|
_feps::codec::Decode,
|
||||||
_npos::scale_info::TypeInfo,
|
_feps::scale_info::TypeInfo,
|
||||||
)])
|
)])
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
|||||||
#derives_and_maybe_compact_encoding
|
#derives_and_maybe_compact_encoding
|
||||||
#vis struct #ident { #single #rest }
|
#vis struct #ident { #single #rest }
|
||||||
|
|
||||||
use _npos::__OrInvalidIndex;
|
use _feps::__OrInvalidIndex;
|
||||||
impl _npos::NposSolution for #ident {
|
impl _feps::NposSolution for #ident {
|
||||||
const LIMIT: usize = #count;
|
const LIMIT: usize = #count;
|
||||||
type VoterIndex = #voter_type;
|
type VoterIndex = #voter_type;
|
||||||
type TargetIndex = #target_type;
|
type TargetIndex = #target_type;
|
||||||
@@ -114,34 +114,34 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_assignment<FV, FT, A>(
|
fn from_assignment<FV, FT, A>(
|
||||||
assignments: &[_npos::Assignment<A, #weight_type>],
|
assignments: &[_feps::Assignment<A, #weight_type>],
|
||||||
voter_index: FV,
|
voter_index: FV,
|
||||||
target_index: FT,
|
target_index: FT,
|
||||||
) -> Result<Self, _npos::Error>
|
) -> Result<Self, _feps::Error>
|
||||||
where
|
where
|
||||||
A: _npos::IdentifierT,
|
A: _feps::IdentifierT,
|
||||||
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
||||||
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>,
|
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>,
|
||||||
{
|
{
|
||||||
let mut #struct_name: #ident = Default::default();
|
let mut #struct_name: #ident = Default::default();
|
||||||
for _npos::Assignment { who, distribution } in assignments {
|
for _feps::Assignment { who, distribution } in assignments {
|
||||||
match distribution.len() {
|
match distribution.len() {
|
||||||
0 => continue,
|
0 => continue,
|
||||||
#from_impl
|
#from_impl
|
||||||
_ => {
|
_ => {
|
||||||
return Err(_npos::Error::SolutionTargetOverflow);
|
return Err(_feps::Error::SolutionTargetOverflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(#struct_name)
|
Ok(#struct_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_assignment<A: _npos::IdentifierT>(
|
fn into_assignment<A: _feps::IdentifierT>(
|
||||||
self,
|
self,
|
||||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||||
) -> Result<_npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>>, _npos::Error> {
|
) -> Result<_feps::sp_std::prelude::Vec<_feps::Assignment<A, #weight_type>>, _feps::Error> {
|
||||||
let mut #assignment_name: _npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>> = Default::default();
|
let mut #assignment_name: _feps::sp_std::prelude::Vec<_feps::Assignment<A, #weight_type>> = Default::default();
|
||||||
#into_impl
|
#into_impl
|
||||||
Ok(#assignment_name)
|
Ok(#assignment_name)
|
||||||
}
|
}
|
||||||
@@ -158,10 +158,10 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
|||||||
all_edges
|
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
|
// NOTE: this implementation returns the targets sorted, but we don't use it yet per
|
||||||
// se, nor is the API enforcing it.
|
// 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 all_targets: BTreeSet<Self::TargetIndex> = BTreeSet::new();
|
||||||
let mut maybe_insert_target = |t: Self::TargetIndex| {
|
let mut maybe_insert_target = |t: Self::TargetIndex| {
|
||||||
all_targets.insert(t);
|
all_targets.insert(t);
|
||||||
@@ -173,22 +173,22 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type __IndexAssignment = _npos::IndexAssignment<
|
type __IndexAssignment = _feps::IndexAssignment<
|
||||||
<#ident as _npos::NposSolution>::VoterIndex,
|
<#ident as _feps::NposSolution>::VoterIndex,
|
||||||
<#ident as _npos::NposSolution>::TargetIndex,
|
<#ident as _feps::NposSolution>::TargetIndex,
|
||||||
<#ident as _npos::NposSolution>::Accuracy,
|
<#ident as _feps::NposSolution>::Accuracy,
|
||||||
>;
|
>;
|
||||||
impl<'a> _npos::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident {
|
impl<'a> _feps::sp_std::convert::TryFrom<&'a [__IndexAssignment]> for #ident {
|
||||||
type Error = _npos::Error;
|
type Error = _feps::Error;
|
||||||
fn try_from(index_assignments: &'a [__IndexAssignment]) -> Result<Self, Self::Error> {
|
fn try_from(index_assignments: &'a [__IndexAssignment]) -> Result<Self, Self::Error> {
|
||||||
let mut #struct_name = #ident::default();
|
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() {
|
match distribution.len() {
|
||||||
0 => {}
|
0 => {}
|
||||||
#from_index_impl
|
#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);
|
let name = vote_field(1);
|
||||||
quote!(
|
quote!(
|
||||||
for (voter_index, target_index) in self.#name {
|
for (voter_index, target_index) in self.#name {
|
||||||
#assignments.push(_npos::Assignment {
|
#assignments.push(_feps::Assignment {
|
||||||
who: voter_at(voter_index).or_invalid_index()?,
|
who: voter_at(voter_index).or_invalid_index()?,
|
||||||
distribution: vec![
|
distribution: vec![
|
||||||
(target_at(target_index).or_invalid_index()?, #per_thing::one())
|
(target_at(target_index).or_invalid_index()?, #per_thing::one())
|
||||||
@@ -329,25 +329,25 @@ pub(crate) fn into_impl(
|
|||||||
let mut inners_parsed = inners
|
let mut inners_parsed = inners
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ref t_idx, p)| {
|
.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()?;
|
let target = target_at(*t_idx).or_invalid_index()?;
|
||||||
Ok((target, *p))
|
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() {
|
if sum >= #per_thing::one() {
|
||||||
return Err(_npos::Error::SolutionWeightOverflow);
|
return Err(_feps::Error::SolutionWeightOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// defensive only. Since Percent doesn't have `Sub`.
|
// 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(),
|
#per_thing::one(),
|
||||||
sum,
|
sum,
|
||||||
);
|
);
|
||||||
|
|
||||||
inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last));
|
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()?,
|
who: voter_at(voter_index).or_invalid_index()?,
|
||||||
distribution: inners_parsed,
|
distribution: inners_parsed,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -167,17 +167,86 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
pub mod onchain;
|
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_runtime::traits::Bounded;
|
||||||
use sp_std::{fmt::Debug, prelude::*};
|
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;
|
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_arithmetic::PerThing;
|
||||||
pub use sp_npos_elections::{
|
pub use sp_npos_elections::{
|
||||||
Assignment, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Support, Supports,
|
Assignment, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, Support,
|
||||||
VoteWeight,
|
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.
|
/// Types that are used by the data provider trait.
|
||||||
pub mod data_provider {
|
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::*;
|
pub use impls::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints,
|
slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure,
|
||||||
Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf,
|
Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases,
|
||||||
Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
|
RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
|
||||||
ValidatorPrefs,
|
ValidatorPrefs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -554,7 +554,7 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for &(ref stash, ref controller, balance, ref status) in &self.stakers {
|
for &(ref stash, ref controller, balance, ref status) in &self.stakers {
|
||||||
log!(
|
crate::log!(
|
||||||
trace,
|
trace,
|
||||||
"inserting genesis staker: {:?} => {:?} => {:?}",
|
"inserting genesis staker: {:?} => {:?} => {:?}",
|
||||||
stash,
|
stash,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
//! Structs and helpers for distributing a voter's stake among various winners.
|
//! 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")]
|
#[cfg(feature = "std")]
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use sp_arithmetic::{
|
use sp_arithmetic::{
|
||||||
@@ -166,44 +166,3 @@ impl<AccountId> StakedAssignment<AccountId> {
|
|||||||
self.distribution.iter().fold(Zero::zero(), |a, b| a.saturating_add(b.1))
|
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 reduce;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
||||||
pub use assignments::{Assignment, IndexAssignment, IndexAssignmentOf, StakedAssignment};
|
pub use assignments::{Assignment, StakedAssignment};
|
||||||
pub use balancing::*;
|
pub use balancing::*;
|
||||||
pub use helpers::*;
|
pub use helpers::*;
|
||||||
pub use phragmen::*;
|
pub use phragmen::*;
|
||||||
pub use phragmms::*;
|
pub use phragmms::*;
|
||||||
pub use pjr::*;
|
pub use pjr::*;
|
||||||
pub use reduce::reduce;
|
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.
|
/// The errors that might occur in this crate and `frame-election-provider-solution-type`.
|
||||||
#[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.
|
|
||||||
#[derive(Eq, PartialEq, RuntimeDebug)]
|
#[derive(Eq, PartialEq, RuntimeDebug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// While going from solution indices to ratio, the weight of all the edges has gone above the
|
/// 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.
|
//! Traits for the npos-election operations.
|
||||||
|
|
||||||
use crate::{
|
use crate::ExtendedBalance;
|
||||||
Assignment, ElectionScore, Error, EvaluateSupport, ExtendedBalance, IndexAssignmentOf,
|
use sp_arithmetic::PerThing;
|
||||||
VoteWeight,
|
use sp_std::{fmt::Debug, ops::Mul, prelude::*};
|
||||||
};
|
|
||||||
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::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// an aggregator trait for a generic type of a voter/target identifier. This usually maps to
|
/// an aggregator trait for a generic type of a voter/target identifier. This usually maps to
|
||||||
/// substrate's account id.
|
/// 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).
|
/// Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance).
|
||||||
pub trait PerThing128: PerThing + Mul<ExtendedBalance, Output = ExtendedBalance> {}
|
pub trait PerThing128: PerThing + Mul<ExtendedBalance, Output = ExtendedBalance> {}
|
||||||
impl<T: PerThing + Mul<ExtendedBalance, Output = ExtendedBalance>> PerThing128 for T {}
|
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