Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ members = [
"primitives/keystore",
"primitives/maybe-compressed-blob",
"primitives/npos-elections",
"primitives/npos-elections/compact",
"primitives/npos-elections/solution-type",
"primitives/npos-elections/fuzzer",
"primitives/offchain",
"primitives/panic-handler",
Expand Down
7 changes: 3 additions & 4 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,15 +548,14 @@ parameter_types! {

sp_npos_elections::generate_solution_type!(
#[compact]
pub struct NposCompactSolution16::<
pub struct NposSolution16::<
VoterIndex = u32,
TargetIndex = u16,
Accuracy = sp_runtime::PerU16,
>(16)
);

pub const MAX_NOMINATIONS: u32 =
<NposCompactSolution16 as sp_npos_elections::CompactSolution>::LIMIT as u32;
pub const MAX_NOMINATIONS: u32 = <NposSolution16 as sp_npos_elections::NposSolution>::LIMIT as u32;

/// The numbers configured here should always be more than the the maximum limits of staking pallet
/// to ensure election snapshot will not run out of memory.
Expand Down Expand Up @@ -593,7 +592,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type RewardHandler = (); // nothing to do upon rewards
type DataProvider = Staking;
type OnChainAccuracy = Perbill;
type CompactSolution = NposCompactSolution16;
type Solution = NposSolution16;
type Fallback = Fallback;
type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight<Runtime>;
type ForceOrigin = EnsureRootOrHalfCouncil;
Expand Down
3 changes: 1 addition & 2 deletions frame/election-provider-multi-phase/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ hex-literal = "0.3.1"
substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" }
sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" }
sp-io = { version = "4.0.0-dev", path = "../../primitives/io" }
sp-npos-elections = { version = "4.0.0-dev", default-features = false, features = [ "mocks" ], path = "../../primitives/npos-elections" }
sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" }
sp-tracing = { version = "4.0.0-dev", path = "../../primitives/tracing" }
frame-election-provider-support = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../election-provider-support" }
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
Expand All @@ -67,6 +67,5 @@ std = [
runtime-benchmarks = [
"frame-benchmarking",
"rand",
"sp-npos-elections/mocks",
]
try-runtime = ["frame-support/try-runtime"]
48 changes: 24 additions & 24 deletions frame/election-provider-multi-phase/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ fn solution_with_size<T: Config>(
size: SolutionOrSnapshotSize,
active_voters_count: u32,
desired_targets: u32,
) -> Result<RawSolution<CompactOf<T>>, &'static str> {
) -> Result<RawSolution<SolutionOf<T>>, &'static str> {
ensure!(size.targets >= desired_targets, "must have enough targets");
ensure!(
size.targets >= (<CompactOf<T>>::LIMIT * 2) as u32,
size.targets >= (<SolutionOf<T>>::LIMIT * 2) as u32,
"must have enough targets for unique votes."
);
ensure!(size.voters >= active_voters_count, "must have enough voters");
ensure!(
(<CompactOf<T>>::LIMIT as u32) < desired_targets,
(<SolutionOf<T>>::LIMIT as u32) < desired_targets,
"must have enough winners to give them votes."
);

Expand All @@ -75,7 +75,7 @@ fn solution_with_size<T: Config>(
// chose a random subset of winners.
let winner_votes = winners
.as_slice()
.choose_multiple(&mut rng, <CompactOf<T>>::LIMIT)
.choose_multiple(&mut rng, <SolutionOf<T>>::LIMIT)
.cloned()
.collect::<Vec<_>>();
let voter = frame_benchmarking::account::<T::AccountId>("Voter", i, SEED);
Expand All @@ -92,7 +92,7 @@ fn solution_with_size<T: Config>(
let rest_voters = (active_voters_count..size.voters)
.map(|i| {
let votes = (&non_winners)
.choose_multiple(&mut rng, <CompactOf<T>>::LIMIT)
.choose_multiple(&mut rng, <SolutionOf<T>>::LIMIT)
.cloned()
.collect::<Vec<T::AccountId>>();
let voter = frame_benchmarking::account::<T::AccountId>("Voter", i, SEED);
Expand Down Expand Up @@ -129,25 +129,25 @@ fn solution_with_size<T: Config>(
let assignments = active_voters
.iter()
.map(|(voter, _stake, votes)| {
let percent_per_edge: InnerOf<CompactAccuracyOf<T>> =
let percent_per_edge: InnerOf<SolutionAccuracyOf<T>> =
(100 / votes.len()).try_into().unwrap_or_else(|_| panic!("failed to convert"));
crate::unsigned::Assignment::<T> {
who: voter.clone(),
distribution: votes
.iter()
.map(|t| (t.clone(), <CompactAccuracyOf<T>>::from_percent(percent_per_edge)))
.map(|t| (t.clone(), <SolutionAccuracyOf<T>>::from_percent(percent_per_edge)))
.collect::<Vec<_>>(),
}
})
.collect::<Vec<_>>();

let compact =
<CompactOf<T>>::from_assignment(&assignments, &voter_index, &target_index).unwrap();
let score = compact.clone().score(&winners, stake_of, voter_at, target_at).unwrap();
let solution =
<SolutionOf<T>>::from_assignment(&assignments, &voter_index, &target_index).unwrap();
let score = solution.clone().score(&winners, stake_of, voter_at, target_at).unwrap();
let round = <MultiPhase<T>>::round();

assert!(score[0] > 0, "score is zero, this probably means that the stakes are not set.");
Ok(RawSolution { compact, score, round })
Ok(RawSolution { solution, score, round })
}

fn set_up_data_provider<T: Config>(v: u32, t: u32) {
Expand Down Expand Up @@ -265,7 +265,7 @@ frame_benchmarking::benchmarks! {
let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1];
// number of targets in snapshot.
let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1];
// number of assignments, i.e. compact.len(). This means the active nominators, thus must be
// number of assignments, i.e. solution.len(). This means the active nominators, thus must be
// a subset of `v` component.
let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1];
// number of desired targets. Must be a subset of `t` component.
Expand Down Expand Up @@ -308,11 +308,11 @@ frame_benchmarking::benchmarks! {

let mut signed_submissions = SignedSubmissions::<T>::get();
for i in 0..c {
let solution = RawSolution {
let raw_solution = RawSolution {
score: [(10_000_000 + i).into(), 0, 0],
..Default::default()
};
let signed_submission = SignedSubmission { solution, ..Default::default() };
let signed_submission = SignedSubmission { raw_solution, ..Default::default() };
signed_submissions.insert(signed_submission);
}
signed_submissions.put();
Expand All @@ -330,7 +330,7 @@ frame_benchmarking::benchmarks! {
let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1];
// number of targets in snapshot.
let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1];
// number of assignments, i.e. compact.len(). This means the active nominators, thus must be
// number of assignments, i.e. solution.len(). This means the active nominators, thus must be
// a subset of `v` component.
let a in
(T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1];
Expand Down Expand Up @@ -369,7 +369,7 @@ frame_benchmarking::benchmarks! {
let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1];
// number of targets in snapshot.
let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1];
// number of assignments, i.e. compact.len(). This means the active nominators, thus must be
// number of assignments, i.e. solution.len(). This means the active nominators, thus must be
// a subset of `v` component.
let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1];
// number of desired targets. Must be a subset of `t` component.
Expand All @@ -378,8 +378,8 @@ frame_benchmarking::benchmarks! {
let size = SolutionOrSnapshotSize { voters: v, targets: t };
let raw_solution = solution_with_size::<T>(size, a, d)?;

assert_eq!(raw_solution.compact.voter_count() as u32, a);
assert_eq!(raw_solution.compact.unique_targets().len() as u32, d);
assert_eq!(raw_solution.solution.voter_count() as u32, a);
assert_eq!(raw_solution.solution.unique_targets().len() as u32, d);

// encode the most significant storage item that needs to be decoded in the dispatch.
let encoded_snapshot = <MultiPhase<T>>::snapshot().unwrap().encode();
Expand Down Expand Up @@ -447,7 +447,7 @@ frame_benchmarking::benchmarks! {
let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1];
// number of targets in snapshot.
let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1];
// number of assignments, i.e. compact.len(). This means the active nominators, thus must be
// number of assignments, i.e. solution.len(). This means the active nominators, thus must be
// a subset of `v` component.
let a in
(T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1];
Expand All @@ -461,11 +461,11 @@ frame_benchmarking::benchmarks! {
// Compute a random solution, then work backwards to get the lists of voters, targets, and
// assignments
let witness = SolutionOrSnapshotSize { voters: v, targets: t };
let RawSolution { compact, .. } = solution_with_size::<T>(witness, a, d)?;
let RawSolution { solution, .. } = solution_with_size::<T>(witness, a, d)?;
let RoundSnapshot { voters, targets } = MultiPhase::<T>::snapshot().unwrap();
let voter_at = helpers::voter_at_fn::<T>(&voters);
let target_at = helpers::target_at_fn::<T>(&targets);
let mut assignments = compact.into_assignment(voter_at, target_at).unwrap();
let mut assignments = solution.into_assignment(voter_at, target_at).unwrap();

// make a voter cache and some helper functions for access
let cache = helpers::generate_voter_cache::<T>(&voters);
Expand All @@ -488,7 +488,7 @@ frame_benchmarking::benchmarks! {
.unwrap();

let encoded_size_of = |assignments: &[IndexAssignmentOf<T>]| {
CompactOf::<T>::try_from(assignments).map(|compact| compact.encoded_size())
SolutionOf::<T>::try_from(assignments).map(|solution| solution.encoded_size())
};

let desired_size = Percent::from_percent(100 - f.saturated_into::<u8>())
Expand All @@ -501,8 +501,8 @@ frame_benchmarking::benchmarks! {
&encoded_size_of,
).unwrap();
} verify {
let compact = CompactOf::<T>::try_from(index_assignments.as_slice()).unwrap();
let encoding = compact.encode();
let solution = SolutionOf::<T>::try_from(index_assignments.as_slice()).unwrap();
let encoding = solution.encode();
log!(
trace,
"encoded size prediction = {}",
Expand Down
40 changes: 20 additions & 20 deletions frame/election-provider-multi-phase/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

//! Some helper functions/macros for this crate.

use super::{CompactTargetIndexOf, CompactVoterIndexOf, Config, VoteWeight};
use super::{Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight};
use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, prelude::*};

#[macro_export]
Expand Down Expand Up @@ -49,18 +49,18 @@ pub fn generate_voter_cache<T: Config>(

/// Create a function that returns the index of a voter in the snapshot.
///
/// The returning index type is the same as the one defined in `T::CompactSolution::Voter`.
/// The returning index type is the same as the one defined in `T::Solution::Voter`.
///
/// ## Warning
///
/// Note that this will represent the snapshot data from which the `cache` is generated.
pub fn voter_index_fn<T: Config>(
cache: &BTreeMap<T::AccountId, usize>,
) -> impl Fn(&T::AccountId) -> Option<CompactVoterIndexOf<T>> + '_ {
) -> impl Fn(&T::AccountId) -> Option<SolutionVoterIndexOf<T>> + '_ {
move |who| {
cache
.get(who)
.and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
.and_then(|i| <usize as TryInto<SolutionVoterIndexOf<T>>>::try_into(*i).ok())
}
}

Expand All @@ -70,11 +70,11 @@ pub fn voter_index_fn<T: Config>(
/// borrowed.
pub fn voter_index_fn_owned<T: Config>(
cache: BTreeMap<T::AccountId, usize>,
) -> impl Fn(&T::AccountId) -> Option<CompactVoterIndexOf<T>> {
) -> impl Fn(&T::AccountId) -> Option<SolutionVoterIndexOf<T>> {
move |who| {
cache
.get(who)
.and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
.and_then(|i| <usize as TryInto<SolutionVoterIndexOf<T>>>::try_into(*i).ok())
}
}

Expand All @@ -98,72 +98,72 @@ pub fn voter_index_fn_usize<T: Config>(
#[cfg(test)]
pub fn voter_index_fn_linear<T: Config>(
snapshot: &Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)>,
) -> impl Fn(&T::AccountId) -> Option<CompactVoterIndexOf<T>> + '_ {
) -> impl Fn(&T::AccountId) -> Option<SolutionVoterIndexOf<T>> + '_ {
move |who| {
snapshot
.iter()
.position(|(x, _, _)| x == who)
.and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(i).ok())
.and_then(|i| <usize as TryInto<SolutionVoterIndexOf<T>>>::try_into(i).ok())
}
}

/// Create a function that returns the index of a target in the snapshot.
///
/// The returned index type is the same as the one defined in `T::CompactSolution::Target`.
/// The returned index type is the same as the one defined in `T::Solution::Target`.
///
/// Note: to the extent possible, the returned function should be cached and reused. Producing that
/// function requires a `O(n log n)` data transform. Each invocation of that function completes
/// in `O(log n)`.
pub fn target_index_fn<T: Config>(
snapshot: &Vec<T::AccountId>,
) -> impl Fn(&T::AccountId) -> Option<CompactTargetIndexOf<T>> + '_ {
) -> impl Fn(&T::AccountId) -> Option<SolutionTargetIndexOf<T>> + '_ {
let cache: BTreeMap<_, _> =
snapshot.iter().enumerate().map(|(idx, account_id)| (account_id, idx)).collect();
move |who| {
cache
.get(who)
.and_then(|i| <usize as TryInto<CompactTargetIndexOf<T>>>::try_into(*i).ok())
.and_then(|i| <usize as TryInto<SolutionTargetIndexOf<T>>>::try_into(*i).ok())
}
}

/// Create a function the returns the index to a target in the snapshot.
///
/// The returned index type is the same as the one defined in `T::CompactSolution::Target`.
/// The returned index type is the same as the one defined in `T::Solution::Target`.
///
/// ## Warning
///
/// Not meant to be used in production.
#[cfg(test)]
pub fn target_index_fn_linear<T: Config>(
snapshot: &Vec<T::AccountId>,
) -> impl Fn(&T::AccountId) -> Option<CompactTargetIndexOf<T>> + '_ {
) -> impl Fn(&T::AccountId) -> Option<SolutionTargetIndexOf<T>> + '_ {
move |who| {
snapshot
.iter()
.position(|x| x == who)
.and_then(|i| <usize as TryInto<CompactTargetIndexOf<T>>>::try_into(i).ok())
.and_then(|i| <usize as TryInto<SolutionTargetIndexOf<T>>>::try_into(i).ok())
}
}

/// Create a function that can map a voter index ([`CompactVoterIndexOf`]) to the actual voter
/// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter
/// account using a linearly indexible snapshot.
pub fn voter_at_fn<T: Config>(
snapshot: &Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)>,
) -> impl Fn(CompactVoterIndexOf<T>) -> Option<T::AccountId> + '_ {
) -> impl Fn(SolutionVoterIndexOf<T>) -> Option<T::AccountId> + '_ {
move |i| {
<CompactVoterIndexOf<T> as TryInto<usize>>::try_into(i)
<SolutionVoterIndexOf<T> as TryInto<usize>>::try_into(i)
.ok()
.and_then(|i| snapshot.get(i).map(|(x, _, _)| x).cloned())
}
}

/// Create a function that can map a target index ([`CompactTargetIndexOf`]) to the actual target
/// Create a function that can map a target index ([`SolutionTargetIndexOf`]) to the actual target
/// account using a linearly indexible snapshot.
pub fn target_at_fn<T: Config>(
snapshot: &Vec<T::AccountId>,
) -> impl Fn(CompactTargetIndexOf<T>) -> Option<T::AccountId> + '_ {
) -> impl Fn(SolutionTargetIndexOf<T>) -> Option<T::AccountId> + '_ {
move |i| {
<CompactTargetIndexOf<T> as TryInto<usize>>::try_into(i)
<SolutionTargetIndexOf<T> as TryInto<usize>>::try_into(i)
.ok()
.and_then(|i| snapshot.get(i).cloned())
}
Expand Down
Loading